我有一个函数 frequencyBy
,我想并行化 . 以下是一个简单的测试用例:
import Control.Parallel.Strategies
import Control.DeepSeq
import System.Environment
frequencyBy :: (a -> b -> Bool) -> [a] -> [b] -> [(a,Int)]
frequencyBy f as bs = map
(\a ->(a, foldr (\b -> if f a b then (+) 1 else id) 0 bs)) as
main :: IO ()
main = do
x:xs <- getArgs
let result = frequencyBy (==) [1::Int .. 10000] [1 .. (read x)] `using`
parList rdeepseq
print $ product $ map snd $ result
我想在 frequencyBy
中并行运行 map
. 我正在尝试使用 parList rdeepseq
实现这一点( main
中的所有其他内容只是为了确保不是所有内容都被优化掉了) . 但是,这并不能理解我在这里做错了什么 .
2 回答
可能是开销减慢了速度,取决于x的大小;如果你工作're doing in each spark is comparable to the time it takes to spawn each spark (and of course there'的调度开销等),那么你会遇到问题 .
您可以尝试parListChunk,例如
parListChunk 64 rdeepseq
;您将不得不尝试找出要使用的块大小 . 虽然您当前的策略是为列表中的每个元素创建一个火花,但parListChunk
为列表中的特定大小的每个块创建一个火花,并使用您在该块的每个元素上按顺序指定的策略 .顺便说一下,
frequencyBy
中的foldr
可能会因为过多的thunk创建而减慢速度;就像是应该解决这个问题
当然,和往常一样,确保使用
-O2
进行编译并使用+RTS -N
运行 .我认为你的并行性太精细了 .
parList
尝试并行评估每个元素,并且对于任何一个元素来说确实没有那么多工作 .当我从
parList
变为parListChunk 500
时,执行时间增加了近50%;因为我和它一样好 .作为参考,我正在使用
x=20000
进行测试 .