这似乎很慢:
(time (doall (map + (range 1000000) (range 1000000))))
"Elapsed time: 13951.664454 msecs"
如何更快地做到这一点?
这似乎很慢:
(time (doall (map + (range 1000000) (range 1000000))))
"Elapsed time: 13951.664454 msecs"
如何更快地做到这一点?
对于初学者,range 不会创建一个数组,它会创建一个惰性序列。
添加两个数字集合的最快方法可能是首先将它们放入数组中,然后进行迭代循环而不是映射。
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>
请注意,这仍然具有从两个范围调用创建和实现惰性序列的开销,在实际性能中,您可能已经在进行求和步骤之前构建了该数据。
除非这是您代码中的性能瓶颈,否则以这种方式做事意味着您不应该首先使用 clojure。使用 clojure 的优点是您可以获得高级不可变数据结构,这会导致引用透明和可并行化的代码。一旦下降到像数组这样的原始 jvm 类型,您就会失去这些优势(以换取更好的性能)。
您可能对 Prismatic 的“开源数组处理库 HipHip 感兴趣,它结合了 Clojure 的表现力和 Java 提供的最快数学运算”。
我只是快速使用它,它似乎确实在表现力和性能之间提供了一个很好的折衷:
注意:我使用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"