3 ms·
So that was a pretty early talk. I don't have benchmark numbers in hand, but I'm reasonably sure that the performance gap isn't that wide any more. Also, there
by lukev 14y ago
So that was a pretty early talk. I don't have benchmark numbers in hand, but I'm reasonably sure that the performance gap isn't that wide any more.
Also, there's a new(er) feature called transients that can allow you to use mutable data structures where needed for performance without changing the structure of your code: (http://clojure.org/transients http://clojure.org/transients).
And you can drop down to mutable Java data structures, if you need to: they are fully supported by Clojure, just not the default.
In general, Clojure's approach is to be thread safe and purely functional by default, but it's not too difficult at all to drop out of that for particular parts of your code you've identified as bottlenecks.
- weareconvo 14y agoHonestly, one of the things that bothers me the most is how Clojure enthusiasts get hand-wavey when people talk about performance. They will often "prove" its performance characteristics instead of providing solid real-world examples, and will often dismiss other peoples' benchmarks as having something to do with the quality of the Clojure code on which the benchmark is run.
- lukev 14y agoWhoa. I didn't dismiss any benchmarks, and I'm happy to back up any of what I've said with real-life experiences. For example, I was working on a system a few weeks back that involves loading several-hundred GB CSV files. I wrote it in a functional style, with several map and filter operations over each of the rows. I was able to program the logic viewing the entire CSV file as a single lazy sequence to transform. After profiling I ended up using Java arrays instead of Clojure vectors as the primary data format for records in the system: given the fact that this app was IO-bound, this resulted in about 20% improvement for that particular use case. However, because Clojure is capable of treating arrays as sequences polymorphically, the change required very few modifications to my code and I was able to maintain a functional style.
- lukev 14y agoAlso, here's a microbenchmark I just threw together in a REPL, since you ask: The operation is to create a map data structure, then, ten million times, add/assoc a key value. The key is the .toString() of a random integer between 1 and 100,000. The value is the integer. Therefore, the resulting map will end up with a size of 100k elements, and be modified 10m times. Except for the map implementation used, the code is identical. I ran each test six times, discard the first three (to allow the JVM to warm up) and took the average result time of the other three. The results on my 2010 MBP: java.util.TreeMap: 8573ms java.util.HashMap: 3243ms Clojure immutable hashmap: 7909ms Clojure immutable treemap: 21248ms Clojure hashmap (using transients): 5113ms Data!
- weareconvo 14y agoI know that, in the Java world, you guys probably don't really understand this fact, but 3x slower is not only bad, it's so bad as to be completely unworkable in the real world. Source: I was a Google engineer for 5 years.