Haskell - 平行映射,减少火花

gat*_*ado 10 parallel-processing performance haskell multicore

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

pmap :: (a -> b) -> [a] -> [b]
pmap f = runEval . parList rseq . map f
Run Code Online (Sandbox Code Playgroud)

但是,我没有看到完美的CPU划分.如果这可能与火花的数量有关,我可以编写一个将列表划分为#ppus段的pmap ,因此创建了最少的火花吗?我试过以下,但是性能(和火花的数量)要差得多,

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)
Run Code Online (Sandbox Code Playgroud)

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

编辑1

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

Don*_*art 9

并行包定义了一些平行的地图策略为您提供:

parMap :: Strategy b -> (a -> b) -> [a] -> [b]
Run Code Online (Sandbox Code Playgroud)

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

parListChunk :: Int -> Strategy a -> Strategy [a]
Run Code Online (Sandbox Code Playgroud)

将列表划分为块,并将策略evalList strat并行应用于每个块.

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


参考资料:并行软件包haddock文档

  • 如果有人访问这个问题,这个姐妹问题的答案可能会有用(特别是rdeepseq),http://stackoverflow.com/questions/5606165/parallel-map-in-haskell (2认同)