Re: Clojure vs Java speed
- From: Oxide Scrubber <jharriman@xxxxxxxxx>
- Date: Thu, 30 Jul 2009 21:15:17 -0400
Jon Harrop wrote:
Oxide Scrubber wrote:Jon Harrop wrote:fft1976 wrote:The JIT can't, but the coder can. If you want a vector of NOn Jul 28, 9:46 pm, Oxide Scrubber <jharri...@xxxxxxxxx> wrote:Right. Writing such algorithms generically incurs huge performancefft1976 wrote:I disagree. I don't think the JIT can do much about the memory layoutJava: 1.5x slower than C as a rule of thumb.I think it can achieve parity.
of the data structures. Compare a vector of complex numbers or of 3D
vectors (NOT of pointers to them) in C/C++ and Java. Run some tests. I
did and I looked at others'.
degradation in Java and Clojure.
double-precision complex numbers in Java that is contiguous in memory,
for example, you could use a Java array of 2xN doubles and index into it
appropriately.
That is not generic.
With Clojure multimethods and macros, you can make it generic.
You cannot write code that is both that short and that efficient in Clojure.
You can write code that is that efficient in Clojure, and the algorithm can be expressed as compactly, but you may need some support macros. Those, however, need only be written once for each novel type you wish to support.
Also, note that this same sort function can be used to sort value types such
as (unboxed) complex numbers with no alterations whatsoever. There is no
need to use syntactic abstractions to workaround any deficiencies, no need
to write custom index functions than handle special indexing for custom
types to work around the lack of value types.
And there isn't in Clojure either if someone else (or you on an earlier project) has done that work already.
Your "value types" are overrated anyway. Locality of memory access patterns is pretty good with the new "garbage first" collector for separate objects allocated close together in time.
With a language lacking syntactic abstractions like Java, perhaps.That workaround sucks because you've either lost polymorphismFor me, 1.5x is a good trade-off for safety though.The JIT can't, but the coder can. If you want a vector of N
double-precision complex numbers in Java that is contiguous in memory,
for example, you could use a Java array of 2xN doubles and index into
it appropriately.
You are on the JVM to interoperate with Java. Syntactic abstraction in
Clojure might help by allowing you to work around these fundamental
deficiencies in the JVM and Java but it is no panacea: the deficiencies
already damaged most of the code you are trying to interoperate with.
If you want high-performance code you might want the high-performance parts not to make calls into Java, or else to be JNI calls, one or the other.
One example where Clojure will do just fine is when you want to do numerics and also present a nice user interface. The numerics code can be very fast (but may not use Java interop) while the GUI code only needs to be fast enough for the UI to feel responsive (and will use Java Swing methods and objects extensively). Your "deficiencies" may have "already damaged" the Swing code, but that's not the CPU-bound part of the system anyway.
or, if you rewrite the entire compiler to use whole program optimizationsSuch optimizations and dynamic loading are mutually exclusive in
and change the calling convention globally, you've lost incremental
compilation and dynamic loading.
languages without "eval" or similar capabilities available at run-time,
yes.
i.e. not Java.
But Clojure is another story.
Stop attacking me.This is fanboy fantasy, not reality.Yes.
I am not attacking you.
Sure you are. I wrote truth, and in response to that I got dumped on with a steaming load of ad hominems.
Clojure has some nice features but its most serious deficiencies areClojure has TCO; you just have to make your use of it explicit (and then
inherited from the JVM and there is nothing Clojure can do about it, e.g.
value types and TCO. Moreover, according to Sun employees on the JVM
languages group this is never likely to be fixed.
the compiler alerts you if it's not really in tail position).
Clojure's recur is only a special case, as I described here:
http://flyingfrogblog.blogspot.com/2009/04/when-celebrity-programmers-attack-guido.html
Clojure offers trampolines to cover more general cases of indirect tail
calls between different functions but it is much slower than real tail call
elimination.
Balderdash.
I'm not sure what you mean by "value types".
http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx
I'm sorry, but I am asking you, not some web site (and especially not some Microsoft web site), what you mean. If you don't want to actually have a constructive dialog, feel free to STFU. Otherwise, actually say something.
If you mean non-pointer types, Clojure has access to the full range of
Java non-pointer types: boolean, byte, short, int, long, float, double,
and char.
The ability to define custom value types is extremely valuable, most notably
in the context of technical computing where you want 32- and 64-bit complex
numbers, 2d vectors, 3d vectors in homogeneous coordinates, quaternions and
dozens of other types to be representable without the overhead of boxing,
heap allocating, stressing the garbage collector and so on.
First of all, I explained in previous posts that you can do that in Java, and with full data abstraction in Clojure.
Second, if you define classes like Complex and Vect in Java with fields of type double, the doubles don't get individually boxed.
Third, the overhead of "heap allocating, stressing the garbage collector and so on" in a modern JVM is about the same as the overhead of stack allocating, on an amortized per-object basis: a pointer bump and whatever construction is done to write values to memory.
Learn how modern garbage collectors work, please.
It can't currently pass them across function call boundaries without
boxing and unboxing, but a) if the function call is consistent, the JIT
can inline it and optimize away the boxing and unboxing, and b) Clojure
has macros, so it's possible to inline a function not being itself
passed across function calls without losing the function-call syntax.
Only if your code is written entirely in Clojure which will not be the case
Why won't it?
you are on the JVM to reuse existing Java libraries
Laughable. You may be on the JVM to get portability, or a top-notch GC, or any combination of things. And if you are on the JVM to use existing Java libraries, that usage might not be in the numeric parts of the code; say file I/O, networking, or GUI code using Java libraries and pure-Clojure numeric code.
Last, but certainly not least, the Java libraries you're using might be existing high-performance numerics libraries for Java! Or Java wrappers around GMP or a similar native-code library. Then the performance of numeric Clojure code is irrelevant.
but those libraries expose these deficiencies of the VM by providing
non-generic interfaces.
A bit of Clojure magic could wrap these in much nicer interfaces even so -- and, using macros or definline judiciously, without any run-time overhead.
As an aside, the JVM even screwed up generics by using type erasure instead
of monomorphization and per-type instantiation at JIT => when the JVM fails
to optimize, generics are extremely slow.
That's why if you need performance you use -server. Besides, Clojure doesn't care about Java's generics making them irrelevant.
Just make a macro version of the function, or even a macro that can take
a function's source code and spit out a macro version of that function.
That only works if the entire source is written in Clojure.
It works if that particular function's source is.
Anyway, the upshot of all this is that "Clojure has some nice features
but its most serious deficiencies are inherited from the JVM and there
is nothing Clojure can do about it" is simply false, because Clojure has
syntactic abstraction and definline and features like that which enable
a user to create seamless workarounds for those so-called "serious
deficiencies". (I especially like the ability to write macros that write
macros!)
Sure. Macros can be nice. But it is not feasible to work around deficiencies
in the VM that have already infected the Java code that you are trying to
interoperate with.
I see that I am arguing not against a rational man, but against some heretofore undiscovered species of religious zealot, from some mystery sect whose articles of faith involve "deficiencies" and "infections" not apparent to the infidel.
I shall probably quit now, because it is generally futile to argue against religious beliefs, however irrational and unfounded in actual logic and evidence.
Perhaps I should have realized sooner that you were not a rational person; when I referenced actual results of actual benchmarks proving Clojure able to hold its own in a numeric-speed pissing contest and just got back an "it's 10x slower" mantra even after disproving that claim.
Oh, well.
Perhaps the best solution for technical users would beWhat is MLVM?
for languages like Scala and Clojure to target MLVM instead of the JVM
http://openjdk.java.net/projects/mlvm/
Are you having difficulty actually saying things in your own words? Pointer chasing doesn't interest me much; that's why I gave up on C and started programming in Lisps.
I suggest you read up on functional programming as well.
I am the author of the world's most profitable book on functional
programming.
Let me guess: "Functional Programming for Dummies" or something on that level?
I'll repeat: I suggest you read up on functional programming, and more specifically, on functional programming methods for number-crunching.
If Scheme can be used for heavy number crunching, and it can, then
Clojure can too.
Scheme is not at all common for number crunching.
Your Google-fu is not strong. Google says otherwise. (Results 1 - 10 of about 46,500 for scheme "number crunching". (0.20 seconds))
Dynamic typing makes performance too unpredictable and makes
optimization too tedious. The vast majority of number crunching
applications are written in statically typed languages because they
are predictably fast.
Horsefeathers. One of the hits in that same Google search says "Scheme programs can beat equivalent C number crunching programs." Another says "Nothing in Scheme precludes fast number crunching." And both of those are visible in the excerpts on the SERP, without even clicking any links.
Many of the "problems" you cite go away with aggressive JIT optimization, which you get if you use the -server flag when you launch the JVM.
.
- References:
- Re: Clojure vs Java speed
- From: Oxide Scrubber
- Re: Clojure vs Java speed
- From: Jon Harrop
- Re: Clojure vs Java speed
- Prev by Date: ANN: 3-DAY MAD ICON SALE - (this offer will not be extended)
- Next by Date: Difference between Windows and Linux GCC compiler
- Previous by thread: Re: Clojure vs Java speed
- Next by thread: Re: Clojure vs Java speed
- Index(es):
Relevant Pages
|