Clojure:为什么 get 这么慢? [英] Clojure: why is aget so slow?
问题描述
在我看来,与 java 数组相比,clojure 向量的性能略有下降.因此,我认为传统智慧"是对于代码中那些对性能至关重要的部分,最好使用 java 数组.
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
如您所见,get 为这个添加增加了大约 800% 的时间.尽管如此,这两种方法仍然比原生 java 慢得多:
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
那么,我的结论应该是 aget 比 nth 慢 80 倍,比 java 中的 []-access 慢 800 倍左右吗?
So, should my conclusion be that aget is 80 times slower than nth, and about 800 times slower than []-access in java?
推荐答案
我怀疑这归结为 aget 函数对原始类型的反射和自动装箱....
I suspect this is down to reflection and autoboxing of the primitive types by the aget function....
幸运的是,aget/aset 为原始数组提供了高性能的重载,避免了反射,并且只进行了直接的数组[i] 访问(参见 此处 和 这里).
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
这篇关于Clojure:为什么 get 这么慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!