首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >clojure pmap与map

clojure pmap与map
EN

Stack Overflow用户
提问于 2013-11-13 19:50:11
回答 3查看 3.8K关注 0票数 7

我在cojure REPL中测试了clojure函数映射和pmap,如下所示。这让我很困惑:为什么并行pmap比map慢?

代码语言:javascript
复制
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**
EN

回答 3

Stack Overflow用户

发布于 2013-11-14 16:02:30

对于每个并行处理任务,都会由于任务协调而产生一定数量的开销。pmap将映射函数分别应用于不同线程中的每个元素。当pmap返回的惰性序列被使用时,消费者线程必须与生产者线程协调。按照定义pmap的方式,产生的每个元素都会产生这种开销。

考虑到这一点,当您使用pmap来计算一个简单的函数时(例如,在您的示例中,对一个数字进行平方),线程协调其活动所需的时间将超过实际计算该值所需的时间。正如文档字符串所说,pmap“仅适用于计算密集型函数,其中f的时间决定了协调开销”(empasis补充道)。在这些情况下,无论您有多少个内核,pmap都会比map花费更长的时间。

要真正看到pmap的好处,你必须选择一个“更难”的问题。在某些情况下,这可能与将输入序列划分为块一样简单。然后,可以使用pmap处理分块序列,然后通过concat运行以获得最终输出。

例如:

代码语言:javascript
复制
(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有效性的方法是在整个算法中将工作划分到不同的位置。例如,假设我们对计算点对之间的欧几里德距离感兴趣。虽然并行化平方函数已被证明是无效的,但我们可能会幸运地并行化整个距离函数。实际上,我们希望在更高的级别上划分任务,但这就是它的要点。

简而言之,并行算法的性能对任务的分区方式很敏感,而且您选择的级别对于测试来说太细粒度了。

票数 17
EN

Stack Overflow用户

发布于 2013-11-13 22:26:12

Rörd是正确的,使用pmap有很大的开销。考虑使用reducers来代替:

代码语言:javascript
复制
(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"
票数 3
EN

Stack Overflow用户

发布于 2013-11-13 20:10:10

创建线程、在线程之间分配工作负载以及重新组合结果都会产生一些开销。您需要一个运行时间比#(* % %)长得多的函数,才能看到pmap带来的速度提升(当然,它还取决于您在问题中没有指定的CPU的核心数量)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19953036

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档