Clojure: why is aget so slow?
arrays, clojure, performance
Solution
I suspect this is down to reflection and autoboxing of the primitive types by the aget function....
Luckily aget/aset have performant overloads for primitive arrays that avoid the reflection and just do a direct array[i] access (See here and here).
You just need to pass a type hint to pick up the right function.
(type xa)
[I ; indicates array of primitive ints
; with type hint on array
;
(time (loop [i 0 s 0]
(if (< i 100000) (recur (inc i)
(+ s (aget ^ints xa i))) s)))
"Elapsed time: 6.79 msecs"
4999950000
; without type hinting
;
(time (loop [i 0 s 0]
(if (< i 100000) (recur (inc i)
(+ s (aget xa i))) s)))
"Elapsed time: 1135.097 msecs"
4999950000
Problem
In my thinking, clojure vectors have a slight performance hit compared to java arrays. As a result I thought that "conventional wisdom" was that for those performance-critical parts of your code, you'd be better off using java arrays. My tests however suggest that this is not true: ``` Clojure 1.3.0 user=> (def x (vec (range 100000))) #'user/x user=> (def xa (int-array x)) #'user/xa user=> (time (loop [i 0 s 0] (if (< i 100000) (recur (inc i) (+ s (nth x i))) s))) "Elapsed time: 16.551 msecs" 4999950000 user=> (time (loop [i 0 s 0] (if (< i 100000) (recur (inc i) (+ s (aget xa i))) s))) "Elapsed time: 1271.804 msecs" 4999950000 ``` As you can see, the aget adds about 800% time to this addition. Both methods still are way slower than native java though: ``` public class Test { public static void main (String[] args) { int[] x = new int[100000]; for (int i=0;i<100000;i++) { x[i]=i; } long s=0; long end, start = System.nanoTime(); for (int i=0;i<100000;i++) { s+= x[i]; } end = System.nanoTime(); System.out.println((end-start)/1000000.0+" ms"); System.out.println(s); } } > java Test 1.884 ms 4999950000 ``` So, should my conclusion be that aget is 80 times slower than nth, and about 800 times slower than []-access in java?