2

这似乎很慢:

(time (doall (map + (range 1000000) (range 1000000))))
"Elapsed time: 13951.664454 msecs"

如何更快地做到这一点?

4

2 回答 2

2

对于初学者,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 类型,您就会失去这些优势(以换取更好的性能)。

于 2013-09-24T21:47:20.987 回答
1

您可能对 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"
于 2013-09-26T16:11:52.757 回答