簡體   English   中英

如何使用Haskell中的策略編寫並行縮減?

[英]How do I write a parallel reduction using strategies in Haskell?

在高性能計算中,總和,產品等通常使用“並行縮減”來計算,該“並行縮減”采用n個元素並在O(log n )時間內完成(給定足夠的並行度)。 在Haskell中,我們通常使用折疊進行此類計算,但評估時間在列表長度中始終是線性的。

Data Parallel Haskell內置了一些內容,但是在列表的通用框架中呢? 我們可以用Control.Parallel.Strategies做到嗎?

所以,假設f是關聯的,我們如何寫

parFold :: (a -> a -> a) -> [a] -> a

所以parFold f xs只需要時間length xs對數?

我不認為列表是正確的數據類型。 因為它只是一個鏈表,所以必須按順序訪問數據。 雖然您可以並行評估項目,但在減少步驟中您將無法獲得太多收益。 如果你真的需要一個List,我認為最好的功能就是

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)

我冒昧地假設你的數據是一個Monoid for mempty,如果這是不可能的,你可以用你自己的空類型替換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)

根據工作的確切分配方式,其中一個可能比其他工作更有效。

如果您可以使用對索引具有良好支持的數據結構(數組,向量,映射等),那么您可以為縮減步驟執行二進制細分,這可能會更好。

這似乎是一個好的開始:

parFold :: (a -> a -> a) -> [a] -> a
parFold f = go
  where
  strategy = parList rseq

  go [x] = x
  go xs = go (reduce xs `using` strategy)

  reduce (x:y:xs) = f x y : reduce xs
  reduce list     = list   -- empty or singleton list

它有效,但並行性並不是那么好。 parListChunks 1000替換parList有所幫助,但在8核機器上加速仍然限制在1.5x以下。

不確定你的parFold功能應該做什么。 如果這是foldr或foldl的並行版本,我認為它的定義是錯誤的。

parFold :: (a -> a -> a) -> [a] -> a

// fold right in haskell (takes 3 arguments)
foldr :: (a -> b -> b) -> b -> [a] -> b

折疊將相同的函數應用於列表的每個元素,並累積每個應用程序的結果。 我想,提出它的並行版本將要求元素的函數應用程序並行完成 - 有點像parList那樣做。

    par_foldr :: (NFData a, NFData b) => (a -> b -> b) -> b -> [a] -> b
    par_foldr f z [] = z
    par_foldr f z (x:xs) = res `using` \ _ -> rseq x' `par` rdeepseq res
                       where x' = par_foldr f z xs
                             res = x `f` x'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM