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

我不明白为什么这个程序使用了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时如何使并行计算发生(保持整体计算纯粹)?

作为参考,更换runIdentityrunST使得它的工作,但在两种情况下,具体的单子的功能不被使用的。


computeP和类似的并行操作中具有Monad约束的原因是在必要时强制顺序计算。 这在[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 ,然后调用computeP ,而transpose2P内部调用computeUnboxedP 。 如果使用Identity monad,则不会强制排序,因此这两个并行计算可以并行运行,因此是嵌套并行。

如果你想保持纯粹的东西,也不想使用ST ,你可以用Eval代替Identity ,这是一个严格的Identity

import Control.Parallel.Strategies
...
go = runEval $ do ...
链接地址: http://www.djcxy.com/p/43015.html

上一篇: What's wrong with using Identity monad with mmultP when using repa?

下一篇: Logical AND strictness with IO monad