Clojure中pmap的更好替代方案,用于在大数据上并行化适度便宜的功能?

Clojure中pmap的更好替代方案,用于在大数据上并行化适度便宜的功能?,clojure,parallel-processing,Clojure,Parallel Processing,使用clojure,我在一个序列中有大量的数据,我想用相对较少的内核(4到8个)并行处理它 最简单的方法是使用pmap而不是map,将我的处理功能映射到数据序列上但在我的案例中,协调开销会导致净损失 我认为原因是pmap假设跨数据映射的函数非常昂贵。查看pmap的源代码,它似乎依次为序列的每个元素构建了一个未来,因此函数的每次调用都发生在一个单独的线程上(在可用内核的数量上循环) 以下是pmap的相关资料来源: (defn pmap "Like map, except f is applie

使用clojure,我在一个序列中有大量的数据,我想用相对较少的内核(4到8个)并行处理它

最简单的方法是使用
pmap
而不是
map
,将我的处理功能映射到数据序列上但在我的案例中,协调开销会导致净损失

我认为原因是
pmap
假设跨数据映射的函数非常昂贵。查看pmap的源代码,它似乎依次为序列的每个元素构建了一个
未来
,因此函数的每次调用都发生在一个单独的线程上(在可用内核的数量上循环)

以下是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

在我的例子中,映射函数没有那么昂贵,但是序列是巨大的(数百万条记录)。我认为创建和取消许多期货的成本是平行收益在间接费用中损失的地方

我对
pmap
的理解正确吗?


clojure中是否有比
pmap
更适合这种低成本但大量重复处理的模式?我正在考虑以某种方式对数据序列进行分块,然后在较大的分块上运行线程这是一种合理的方法吗?clojure的习惯用法会起作用吗?

您可以使用某种手动实现的map/reduce。还要看一下框架

“有助于并行编写和运行Clojure代码的分布式计算系统-跨内核和处理器”

这个问题:在非常相似的上下文中也解决了这个问题


目前最好的答案是使用
分区
将其分解成块。然后将映射函数映射到每个块上。然后重新组合结果。map-reduce样式。

遗憾的是,这还不是一个有效的答案,但将来需要注意的是Rich在Java 7中使用fork/join库的工作。如果你看看他在Github上的分支,他做了一些工作,最后我看到早期的回报是惊人的。 Rich尝试过的例子


在前面关于此线程和类似线程的回答中提到的fork/join工作最终作为库产生了成果,这可能值得一看。

swarmiji如果是Clojure中的分布式计算库。我得到的印象是,这次静默更多地关注于单系统并行执行。其想法是增加块大小,以便在填充所有内核的同时,克服协调开销。不是所有的数据集都有这样的最佳点。啊哈。我需要在一个额外的抽象层次上思考。I
pmap
块上的函数,该函数将
map
我的处理函数映射到块的每个成员上。这就是你的意思吗?必须小心不要(悄悄地!)跳过带有
partition
的一些输入,因为它从不生成比指定的块更小的块。例如,
(分区5[12])
的计算结果为en empty lazy seq
clojure.contrib.seq utils/partition all
(即将成为
clojure.contrib.seq/partition all
)将一个简短的最后一个块放在一起(
((12))
,参数如上)。(分区5’()[12])将把小的块留在最后,不会丢弃任何东西。Clojure reducers库现在是更好的解决方案吗?事实上,我发现现在可以用Java6、github的Clojure“par”分支和Rich Hickey提供的jsr166y.jar文件来尝试这一点:Ohhh真的吗?可能不得不给一个看看,因为PAR看起来惊人。谢谢你的提示,因为我错过了这个。这就是最终成为reducers库的原因吗?如果适用的话,别忘了利用备忘录。