【问题标题】:How can I compute the sum of a large list of numbers in parallel using Clojure如何使用 Clojure 并行计算大量数字的总和
【发布时间】:2013-02-11 17:59:50
【问题描述】:

我正在尝试弄清楚如何使用 clojure 将一个简单的操作有效地并行应用于一个大序列。我希望能够使用并行解决方案来利用我机器上的多个内核来实现一些加速。

我正在尝试将 pmap 与 partition-all 结合使用,以减少为输入序列中的每个项目创建未来的开销。不幸的是,partition-all 强制对每个分区序列进行完整评估。这会在我的机器上导致 OutOfMemoryError。

(defn sum [vs]
  (reduce + vs))

(def workers
  (+ 2 (.. Runtime getRuntime availableProcessors)))

(let
  [n 80000000
   vs (range n)]

  (time (sum vs))
  (time (sum (pmap sum (partition-all (long (/ n workers)) vs)))))

如何将 sum 应用于大型输入集,并超越串行实现的性能?

解决方案

感谢 @Arthur Ulfeldt 指出 reducers 库。这是使用减速器的解决方案。此代码显示了在多核机器上运行时预期的性能改进。 (注意:我已将 vs 改成一个函数,以使计时更准确)

(require '[clojure.core.reducers :as r])

(let
  [n 80000000
   vs #(range n)]

  (time (reduce + (vs)))
  (time (r/fold + (vs)))

【问题讨论】:

  • 这些块是错误的方式吗? (partition-all workers vs) 创建长度为 workers(/ n workers) 序列。你不想(partition-all (long (/ n workers)) vs)吗?
  • @A.Webb,感谢您的更正。我会修改问题。此修复有助于使并行版本更快一些,但它仍然无法击败串行实现,并且在非常大的输入上仍然会耗尽内存。

标签: clojure parallel-processing


【解决方案1】:

在使用 pmap 时,我发现需要相当大的块来克服切换和未来的开销尝试使用 10,000 的块大小以实现与 + 一样快的操作。潜在收益受限于生成块的开销。这会产生一个平衡可用核心和制作块所需时间的最佳值。在这种情况下,以+ 作为工作负载,我无法使其比单线程选项更快。

如果您有兴趣在不使用 pmap 并可能使用 fork/join 的情况下执行此操作,请查看新的(ish)reducers library

OOM 情况来自第一个测试实现来自(range n) 的惰性序列,然后将其保留以便可以传递给第二个序列。

如果我通过定义slow+ 函数使 + 函数变得更慢,并使用单线程、块上的 pmap 和带 forkJoin 的减速器之间的差异变得可见:

user> *clojure-version*                                                             
{:major 1, :minor 5, :incremental 0, :qualifier "RC15"}
(require '[clojure.core.reducers :as r]) 

(def workers
  (+ 2 (.. Runtime getRuntime availableProcessors)))

(defn slow+
  ([] 0)
  ([x] x)
  ([x y] (reduce + (range 100000)) (+ x y)))

(defn run-test []
  (let [n 8000]
   (time (reduce slow+ (range n)))
   (time (reduce slow+ (pmap #(reduce slow+ %) (partition-all (* workers 100) (range n)))))
   (time (r/fold slow+ (vec (range n)))))) 

user> (run-test)
"Elapsed time: 28655.951241 msecs" ; one thread
"Elapsed time: 6975.488591 msecs"  ; pmap over chunks
"Elapsed time: 8170.254426 msecs"  ; using reducer

【讨论】:

    猜你喜欢
    • 2015-03-18
    • 1970-01-01
    • 2021-11-24
    • 2020-11-22
    • 2021-01-19
    • 1970-01-01
    • 1970-01-01
    • 2021-05-23
    • 2020-12-09
    相关资源
    最近更新 更多