我不認爲列表是正確的數據類型。因爲它只是一個鏈表,所以必須按順序訪問數據。雖然您可以並行評估這些項目,但在減少步驟中不會獲得太多收益。如果你真的需要一個名單,我認爲最好的功能將只是
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