【发布时间】: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