【问题标题】:Haskell -- parallel map that makes less sparksHaskell——产生更少火花的平行映射
【发布时间】:2011-08-23 13:23:48
【问题描述】:

我想在 Haskell 中编写一个尽可能高效的并行映射函数。我最初的尝试,似乎是目前最好的,就是简单地写,

pmap :: (a -> b) -> [a] -> [b]
pmap f = runEval . parList rseq . map f

但是,我没有看到完美的 CPU 划分。如果这可能与火花的数量有关,我是否可以编写一个 pmap 将列表划分为 # of cpus 段,从而创建最少的火花?我尝试了以下方法,但性能(和火花数)要差得多,

pmap :: (a -> b) -> [a] -> [b]
pmap f xs = concat $ runEval $ parList rseq $ map (map f) (chunk xs) where
    -- the (len / 4) argument represents the size of the sublists
    chunk xs = chunk' ((length xs) `div` 4) xs
    chunk' n xs | length xs <= n = [xs]
                | otherwise = take n xs : chunk (drop n xs)

较差的性能可能与较高的内存使用量相关。原始 pmap 在 24 核系统上确实可以扩展,所以并不是我没有足够的数据。 (我桌面上的 CPU 数量是 4,所以我只是硬编码)。

编辑 1

使用+RTS -H512m -N -sstderr -RTS 的一些性能数据在这里:

【问题讨论】:

  • 调整parMap 为每个内核触发一次并不是一个可靠的方法——每个元素可能需要不同的计算量。例如,在简单的 fib 实现中,每个连续元素的工作量都会显着增加,因此将最后一个 n 元素放在同一个 spark 中会导致很少的并行性。

标签: performance haskell parallel-processing multicore


【解决方案1】:

parallel 包为您定义了许多并行映射策略

parMap :: Strategy b -> (a -> b) -> [a] -> [b]

parList 和 map 的组合,以及对列表分块的特定支持:

parListChunk :: Int -> Strategy a -> Strategy [a]

将列表分成块,并将策略evalList strat并行应用于每个块。

您应该能够使用这些组合来获得您想要的任何激发行为。或者,为了获得更多控制,the Par monad 包,用于控制(纯粹)创建的线程数量。


参考资料:haddock docs for the parallel package

【讨论】:

  • 很好,可以控制火花的数量。抱歉,我在 hackage 上错过了它……至少它现在在 stackoverflow 上。不幸的是,性能并没有好多少,但可能是我的错。奇怪的是,-g1 用于并行垃圾收集使垃圾收集状态下降,但运行时并没有改变......
  • @gatoatigrado:尝试与-qa-qg 一起使用。这两个选项有时有助于并行程序的 gc 性能。但有时它们会更糟,所以一定要测试它们。
  • 如果有人访问这个问题,这个姐妹问题的答案可能会有用(特别是 rdeepseq),stackoverflow.com/questions/5606165/parallel-map-in-haskell
猜你喜欢
  • 2014-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-13
  • 2017-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多