6

我不明白为什么这个程序使用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.

我没有嵌套计算,我没有调用computeor copy,并且我用来进行计算的所有内容都在同一个 monad 中。这与惰性评估有关吗?如果是这样,我如何在使用 Identity monad 时进行并行计算(以保持整体计算纯粹)?

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

4

1 回答 1

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。如果您使用Identitymonad,则没有强制排序,因此这两个并行计算都可以并行运行,因此嵌套并行。

如果你想保持纯洁又不想使用ST,你可以替换IdentityEval,这是一个严格的版本Identity

import Control.Parallel.Strategies
...
go = runEval $ do ...
于 2016-06-16T08:57:29.100 回答