Clojure reducer - 有效地将函数应用于并行的两个向量

Mic*_*ert 5 parallel-processing clojure

将两个或多个大型向量组合在一起的最有效和最惯用的方法是什么?这就是我一直在做的事情.在我的应用程序中,我使用矩阵,因此每个操作比添加两个双精度要贵一些.使用range驱动倍感觉有点笨拙.

(require '[clojure.core.reducers :as r])

(def a (mapv (fn [_] (rand 100)) (range 100000)))
(def b (mapv (fn [_] (rand 100)) (range 100000)))
(r/foldcat (r/map #(+ (a %) (b %)) (range (count a))))
Run Code Online (Sandbox Code Playgroud)

计算range可能最终成为多核CPU上最昂贵的位,因为它是唯一的非并行部分并涉及序列.

Mic*_*ert 0

实际上看起来 Clojure 1.8 有一个很好的答案,该模式已经在 Clojure 1.7 中使用map-index.

理想情况下,我希望像map-index这样需要多个集合map,但这就可以了。它看起来相当 clojuresque,不像我在一定范围内的笨拙折叠。

(defn combine-with [op a-coll] (fn [i b-el] (op (a-coll i) b-el)))

(map-indexed (combine-with + a) b)
Run Code Online (Sandbox Code Playgroud)

只需要等待 1.8 的性能:http://dev.clojure.org/jira/browse/CLJ-1553

以下是 6 核 CPU 上的一些时序:

(def irange (vec (range (count a))))  ; precompute

(c/quick-bench (def ab (r/foldcat (r/map #(+ (a %) (b %)) irange))))
             Execution time mean : 1.426060 ms

(c/quick-bench (def abt (into [] (map-indexed (combine-with + a)) b)))
             Execution time mean : 9.931824 ms
Run Code Online (Sandbox Code Playgroud)