Clojure中的pmap与map比较。

8

我在Clojure REPL中测试了map和pmap函数,如下所示。这让我感到困惑:为什么并行的pmap比map更慢?

user=> (def lg (range 1 10000000))
user=> (time (def rs (doall (pmap #(* % %) lg))))

"Elapsed time: **125739.056** msecs"

# -------------------------------------------------------
user=> (def lg (range 1 10000000))
user=> (time (def rs (doall (map #(* % %) lg))))

"Elapsed time: **5804.485** msecs"

**PS: the machine has 8 cores**
3个回答

22
每个并行处理任务都存在由于任务协调而带来的一定开销。`pmap` 将映射函数应用于每个元素以在不同的线程中单独执行。当由`pmap`返回的惰性序列被使用时,消费者线程必须与生产者线程进行协调。根据`pmap`的定义方式,这种开销会针对每个生成的元素发生。
考虑到这一点,当您使用`pmap`计算一个简单的函数(例如像您的示例中平方一个数字)时,协调线程活动所花费的时间比实际计算值所需的时间更长。正如文档字符串所说,`pmap`仅适用于“计算密集型”函数,“其中 f 的时间支配了协调开销”(加重强调)。在这些情况下,无论拥有多少个内核,`pmap`都需要比`map`更长的时间才能完成。
要从`pmap`中真正获得好处,您必须选择一个“更难”的问题。在某些情况下,这可能就是将输入序列分成块的简单操作。然后可以使用`pmap`处理块序列,然后通过`concat`运行以获得最终输出。
例如:
(defn chunked-pmap [f partition-size coll]
  (->> coll                           ; Start with original collection.

       (partition-all partition-size) ; Partition it into chunks.

       (pmap (comp doall              ; Map f over each chunk,
                   (partial map f)))  ; and use doall to force it to be
                                      ; realized in the worker thread.

       (apply concat)))               ; Concatenate the chunked results
                                      ; to form the return value.

然而,将序列分区并在最后连接块也会产生一定的开销。例如,在我的机器上,对于您的示例,chunked-pmap 的性能仍然比 map 差很多。但是,对于某些函数来说,它可能是有效的。

改善pmap效率的另一种方法是在整体算法的不同位置分割工作。例如,假设我们想要计算点对之间的欧几里得距离。虽然并行化平方函数被证明是无效的,但我们可能会尝试并行化整个距离函数。实际上,我们希望以更高级别的方式分区任务,但这就是其要义。

简而言之,并行算法的性能对任务分割的方式非常敏感,您选择了过于细粒度的级别进行测试。


3
Rörd说得对,使用pmap会产生很大的开销。考虑改用reducers代替:
(def l (range 10000000))

(time (def a (doall (pmap #(* % %) l))))
"Elapsed time: 14674.415781 msecs"

(time (def a (doall (map #(* % %) l))))
"Elapsed time: 1119.107447 msecs"

(time (def a (doall (into [] (r/map #(* % %) l)))))
"Elapsed time: 1049.754652 msecs"

请确保在您的系统上与 (time (def a (mapv #(* % %) l))) 进行比较,并检查 Clojure 版本。 - ctpenrose

2

创建线程、将工作负载分配给它们并重新组合结果都会带来一些开销。你需要一个运行时间显著长于#(* % %)的函数才能从pmap中看到速度提升(当然,这也取决于你的CPU核心数,你在问题中没有指定)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接