我不认为列表是正确的数据类型。因为它只是一个链表,所以必须按顺序访问数据。虽然您可以并行评估这些项目,但在减少步骤中不会获得太多收益。如果你真的需要一个名单,我认为最好的功能将只是
parFold f = foldl1' f . withStrategy (parList rseq)
也许
parFold f = foldl1' f . withStrategy (parBuffer 5 rseq)
如果还原步骤是复杂的,你可以通过细分列表这样得到的增益:
parReduce f = foldl' f mempty . reducedList . chunkList . withStrategy (parList rseq)
where
chunkList list = let (l,ls) = splitAt 1000 list in l : chunkList ls
reducedList = parMap rseq (foldl' f mempty)
我已经采取了假设你的数据的自由是mempty一个Monoid
,如果无法做到这一点,你可以用自己的空类型更换mempty,或者更糟的情况下,使用foldl1'
。
从这里使用Control.Parallel.Strategies
有两个运营商。 parList
并行评估列表中的所有项目。之后,chunkList
将列表分成1000个元素的块。然后,这些块中的每一块随后由parMap
并行减少。
您也可以尝试
parReduce2 f = foldl' f mempty . reducedList . chunkList
where
chunkList list = let (l,ls) = splitAt 1000 list in l : chunkList ls
reducedList = parMap rseq (foldl' f mempty)
根据工作究竟是如何分布的,其中之一可能比其他人更有效。
如果您可以使用对索引有很好支持的数据结构(数组,矢量,映射等),那么您可以对缩减步骤执行二进制细分,总体来说可能会更好。
正如人们已经注意到的,list是递归并行分割的一个糟糕的数据结构。你需要某种二叉树/绳索结构,如Fortress语言:http://labs.oracle.com/projects/plrg/Publications/ICFPAugust2009Steele.pdf – sclv 2010-10-27 00:56:42