在使用repa时使用Identity monad与mmultP有什么问题?

时间:2016-06-13 05:40:33

标签: haskell parallel-processing repa

我不明白为什么这个程序使用repa

import Data.Array.Repa
import Data.Array.Repa.Algorithms.Matrix
import Data.Functor.Identity

go = runIdentity $ do
  let mat = fromListUnboxed (ix2 2 2) [1..4]
  let ins = fromListUnboxed (ix2 2 1) [1, 1]
  mmultP mat ins

给了我以下警告:

Data.Array.Repa: Performing nested parallel computation sequentially.
  You've probably called the 'compute' or 'copy' function while another
  instance was already running. This can happen if the second version
  was suspended due to lazy evaluation. Use 'deepSeqArray' to ensure
  that each array is fully evaluated before you 'compute' the next one.

我没有嵌套计算,我没有调用computecopy,我用来进行计算的所有东西都在同一个monad中。是否与懒惰评估有关?如果是这样,如何在使用Identity monad时进行并行计算(以保持整体计算纯净)?

作为参考,将runIdentity替换为runST会使其正常工作,尽管在任何一种情况下都没有使用特定monad的功能。

1 个答案:

答案 0 :(得分:2)

Monad和类似的并行操作中具有computeP约束的原因是在需要时强制进行顺序计算。 [Haskell中的并行和并发编程], Monads和computeP 小节中对此进行了描述。

在您的情况下,问题似乎是由mmultP的内部实施引起的:

mmultP  :: Monad m
        => Array U DIM2 Double 
        -> Array U DIM2 Double 
        -> m (Array U DIM2 Double)

mmultP arr brr 
 = [arr, brr] `deepSeqArrays` 
   do   trr      <- transpose2P brr
        let (Z :. h1  :. _)  = extent arr
        let (Z :. _   :. w2) = extent brr
        computeP 
         $ fromFunction (Z :. h1 :. w2)
         $ \ix   -> R.sumAllS 
                  $ R.zipWith (*)
                        (unsafeSlice arr (Any :. (row ix) :. All))
                        (unsafeSlice trr (Any :. (col ix) :. All))

首先调用transpose2P,然后调用computePtranspose2P内部调用computeUnboxedP。如果使用Identity monad,则没有强制排序,因此这两个并行计算可以并行运行,因此嵌套并行。

如果您想保持纯净并且不想使用ST,则可以将Identity替换为Eval,这是Identity的严格版本:

import Control.Parallel.Strategies
...
go = runEval $ do ...