我的目標是有一個平行foldr函數。起初,它似乎 而直截了當地實現,這是我腦子裏想的:更多通用parfoldr比這
首先打破了輸入列表轉換成基於 核心(numCapabilities
)的分區數目。然後將foldr應用於每個分區,其中 將導致每個分區的摺疊值列表。然後在該列表上再次執行 摺疊以獲得最終值。
listChunkSize = numCapabilities
chunk n [] = []
chunk n xs = ys : chunk n zs
where (ys,zs) = splitAt n xs
parfoldr f z [] = z
parfoldr f z xs = res
where
parts = chunk listChunkSize xs
partsRs = map (foldr f z) parts `using` parList rdeepseq
res = foldr f z partsRs
上面的代碼不工作,因爲明顯 foldr相似,(a -> b -> b) -> b -> [a] -> b
,的定義意味着輸入列表 類型是(當然,也可以)從蓄壓器和結果類型不同。
例如,
1)foldr (+) 0 [1..10]
=>列表類型=累加器類型(整數)
2)foldr (\i acc -> (i>5) && acc) True [1..10]
=>列表類型(整數)! =累加器類型(布爾)
所以,上面看我的代碼,所述映射將產生類型b
,然後將其作爲參數傳遞給第二foldr相似傳遞的列表。但第二個 foldr接受類型爲a
的列表。所以,這是行不通的。
醜陋的解決辦法是爲 提供不同類型的簽名parfoldr,例如 parfoldr :: (NFData a) => (a -> a -> a) -> a -> [a] -> a
這會工作,但那麼它是不完全等同於FOLDR。例如 1上面會做得很好,但不是例2 所以,問題1:如何定義parfoldr有相同類型的簽名 爲foldr相似?
比較2倍:
input = [1..1000000]
seqfold = foldr (+) 0
parfold = parfoldr (+) 0
我得到的FOLL。雙核機上的時間: (無-threaded標誌)
$ ./test
seqfold: 4.99s
parfold: 25.16s
(上-threaded標誌)從這些測量
$ ./test
seqfold: 5.32s
parfold: 25.55s
$ ./test +RTS -N1
seqfold: 5.32s
parfold: 25.53s
$ ./test +RTS -N2
seqfold: 3.48s
parfold: 3.68s
$ ./test +RTS -N3
seqfold: 3.57s
parfold: 2.36s
$ ./test +RTS -N4
seqfold: 3.03s
parfold: 1.70s
觀察:
foldr相似,似乎給當核心數量增加時,運行時間減少。 這是爲什麼?
parfold提供更好的運行時間爲N => 3
任何改進的建議和想法表示讚賞:)
有趣的想法。不幸的是,據我所知,平行褶皺不以廣義形式存在...... – alternative