这似乎很慢:
(time (doall (map + (range 1000000) (range 1000000))))
"Elapsed time: 13951.664454 msecs"
如何更快地完成?
答案 0 :(得分:2)
对于初学者来说,范围不会产生数组,它会产生一个懒惰的序列。
添加两个数字集合的最快方法可能是首先将它们放在数组中,然后执行迭代循环而不是映射。
user> (time (let [a (int-array (range 1000000))
b (int-array (range 1000000))]
(dotimes [i 1000000]
(aset a i (+ (aget b i) (aget a i))))
a))
"Elapsed time: 771.100395 msecs"
#<int[] [I@4233eba0>
user>
请注意,这仍然存在从两个范围调用创建和实现延迟seq的开销,在实际性能中,您可能已经在进入求和步骤之前构建了数据。
除非这是代码中的性能瓶颈,否则以这种方式执行操作意味着您不应该首先使用clojure。使用clojure的优点是可以获得高级不可变数据结构,从而实现引用透明且可并行化的代码。一旦你下载到像数组这样的原始jvm类型,你将失去这些优势(换取更好的性能)。
答案 1 :(得分:1)
你可能对Prismatic的"open-source array processing library HipHip, which combines Clojure's expressiveness with the fastest math Java has to offer"感兴趣。
我只是快速使用它,它似乎在表现力和表现之间提供了一个很好的折衷方案:
注意:我正在使用Criterium对此进行基准测试,因为它减少了在JVM上进行基准测试的一些问题。
(require '[criterium.core :refer [quick-bench]])
(quick-bench (doall (map + (range 1000000) (range 1000000))))
;=> "Execution time mean : 791.955406 ms"
(require '[hiphip.int :as h])
(quick-bench (h/amap [x (h/amake [i 1000000] i)
y (h/amake [i 1000000] i)]
(+ x y)))
;=> "Execution time mean : 20.540645 ms"