在Clojure中更好地替代pmap,以便在大数据上并行化适中的廉价函数?

Ale*_*ard 29 parallel-processing clojure

使用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

Run Code Online (Sandbox Code Playgroud)

在我的情况下,映射函数并不昂贵但序列很大(数百万条记录).我认为创建和解除引用许多未来的成本是平行增益在开销中丢失的地方.

我的理解是pmap正确的吗?

对于这种低成本但大规模重复处理而言,在clojure中是否有更好的模式pmap?我正在考虑以某种方式分块数据序列,然后在更大的块上运行线程.这是一个合理的方法,什么是clojure成语?

Art*_*ldt 20

这个问题:如何有效地应用中等权重并行功能也可以在非常类似的环境中解决这个问题.

目前最好的答案是用 partition它来分解成块.然后将map函数映射到每个块上.然后重新组合结果.映射简化风格.

  • 必须注意不要(静默!)跳过一些带有`partition`的输入,因为它永远不会产生比指定的更小的块.例如`(分区5 [1 2])`评估为空懒惰seq!`clojure.contrib.seq-utils/partition-all`(很快就是`clojure.contrib.seq/partition-all`)将一个简短的最后一个块放在一起(`((1 2))`带参数如上所述) . (13认同)
  • 我们的想法是增加块大小,以便在仍然填充所有核心的同时击败协调开销.并非所有数据集都有这样的甜蜜点. (3认同)
  • Clojure Reducer库现在是更好的解决方案吗? (2认同)

Run*_*ult 5

可悲的是,还不是一个有效的答案,但是未来需要注意的是Rich在Java 7中使用fork/join库的工作.如果你在github上查看他的Par分支,他已经完成了一些工作,最后我看到了早期的回报令人惊叹.

Rich尝试它的例子.

http://paste.lisp.org/display/84027

  • 糊状物已经死了 (3认同)
  • 实际上我发现现在可以尝试使用Java6,来自github的Clojure"par"分支和Rich Hickey提供的jsr166y.jar文件:http://cloud.github.com/downloads/richhickey/clojure/jsr166y .罐 (2认同)