我不明白为什么这个程序使用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.
我没有嵌套计算,我没有调用compute
或copy
,我用来进行计算的所有东西都在同一个monad中。是否与懒惰评估有关?如果是这样,如何在使用Identity monad时进行并行计算(以保持整体计算纯净)?
作为参考,将runIdentity
替换为runST
会使其正常工作,尽管在任何一种情况下都没有使用特定monad的功能。
答案 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
,然后调用computeP
,transpose2P
内部调用computeUnboxedP
。如果使用Identity
monad,则没有强制排序,因此这两个并行计算可以并行运行,因此嵌套并行。
如果您想保持纯净并且不想使用ST
,则可以将Identity
替换为Eval
,这是Identity
的严格版本:
import Control.Parallel.Strategies
...
go = runEval $ do ...