Haskell具有“ par”和“ pseq”

时间:2019-05-05 10:17:04

标签: haskell parallel-processing ghc

我正在Haskell中进行一些并行性实验。其中一部分是检查策略与普通parpseq组合器之间的差异。

我创建了一个像这样的函数:

parMap :: NFData b => (a -> b) -> [a] -> [b]
parMap _ [] = []
parMap f (a:as) =
  let v = f a
      vs = parMap f as
  in rnf v `par` vs `pseq` v : vs

我正在尝试使用尽可能少的库(因此没有Strategies,没有Par)以及像Haskell那样的抽象层来实现并行化。

使用此功能,我尝试使用以下两个功能之一执行矩阵矩阵乘法:

matmultListPar :: (Num a, NFData a) => [[a]] -> [[a]] -> [[a]]
matmultListPar a b = parMap multiplyRowByEachColumn a
  where multiplyRowByEachColumn r = map (\c -> sum . zipWith (*) r $ c) $ b'
        b' = transpose b

matmultListParChunks :: (Num a, NFData a) => Int -> [[a]] -> [[a]] -> [[a]]
matmultListParChunks size a b
  = let
        chunks = toChunks size a
        b' = transpose b
    in concat $ parMap (flip matmultList $ b) chunks

matmultList的定义如下:

matmultList :: (Num a) => [[a]] -> [[a]] -> [[a]]
matmultList a b = fmap multiplyRowByEachColumn a
  where multiplyRowByEachColumn r = fmap (\c -> sum $ zipWith (*) r c) $ b'
        b' = transpose b

还有toChunks

toChunks :: Int -> [a] -> [[a]]
toChunks _ [] = []
toChunks size list
  = let (i, f) = splitAt size list
    in i : (toChunks size f)

为清楚起见-矩阵以行为主存储。

我的问题以及因此的问题是:

  1. 在将策略parList rdeepseq应用于纯粹的matmultList时,我在两个内核上的速度几乎提高了两倍。使用我的parMap时,加速几乎没有。

  2. 使用-s开关检查RTS的火花统计信息,我可以看到parMap的大多数火花都是GC生成的(在转换为Strategy时)。

  3. 您可以猜到我的parMap(以criterion基准衡量)并没有达到并行加速,而我的策略是

我在检查Haskell库代码时注意到,par组合器使用函数par#进行激增,而策略使用类似spark#的事物(我再也找不到它了,所以我可能错了)。

我需要在rnf中使用parMap,因为a可能是[Double],所以激发WHNF是不够的(我在不同地方做了force的实验,因为好)。

是由于我的错误实现,太细粒度的计算(GC火花)还是par与策略之间的差异而导致的提速不足?还是完全其他?如何使用parpseq实现加速?

0 个答案:

没有答案