使用 clojure,我的序列中有大量数据,我想使用相对较少的内核(4 到 8)并行处理它。
最简单的方法是使用 pmap
而不是 map
,将我的处理函数映射到数据序列上。 但在我的案例中,协调开销导致净损失。
我认为原因是 pmap
假设跨数据映射的函数非常昂贵。查看 pmap 的源代码,它似乎依次为序列中的每个元素构造一个 future
,因此该函数的每次调用都发生在单独的线程上(循环可用核心的数量)。
这是 pmap 源代码的相关部分:
(defn pmap
"Like map, except f is applied in parallel. Semi-lazy in that the
parallel computation stays ahead of the consumption, but doesn't
realize the entire result unless required. Only useful for
computationally intensive functions where the time of f dominates
the coordination overhead."
([f coll]
(let [n (+ 2 (.. Runtime getRuntime availableProcessors))
rets (map #(future (f %)) coll)
step (fn step [[x & xs :as vs] fs]
(lazy-seq
(if-let [s (seq fs)]
(cons (deref x) (step xs (rest s)))
(map deref vs))))]
(step rets (drop n rets))))
;; multi-collection form of pmap elided
就我而言,映射函数并不昂贵,但序列很大(数百万条记录)。我认为创建和取消引用许多 future 的成本是并行增益在开销中损失的地方。
我对 pmap
的理解正确吗?
在 clojure 中是否有比 pmap
更好的模式来实现这种低成本但大量重复的处理?我正在考虑以某种方式对数据序列进行分块,然后在更大的 block 上运行线程。 这是一种合理的方法吗?哪些 Clojure 习惯用法可行?
最佳答案
这个问题:how-to-efficiently-apply-a-medium-weight-function-in-parallel也在非常相似的环境中解决了这个问题。
当前最好的答案是使用分区
将其分成 block 。然后将映射函数 pmap 到每个 block 上。然后重新组合结果。映射缩减风格。
关于clojure - Clojure 中 pmap 的更好替代方案,用于在大数据上并行化适度廉价的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2103599/