使用STArray的Haskell并行计算

时间:2012-04-09 20:52:39

标签: arrays haskell parallel-processing monads state-monad

我正在尝试并行执行计算,并将结果写入STArray。我认为这段代码显示了我正在尝试做的事情。但是,我收到了编译错误。

import Control.Monad
import Control.Monad.ST
import Control.Parallel
import Data.Array.ST

main = do
    arr <- newArray ((0,0), (5,5)) 0 :: ST s (STArray s (Int, Int) Int)
    runSTArray $ do
        par (writeArray arr (1,1) 17) (writeArray arr (2,2) 23)
        return arr
    print arr

我该怎么做?

2 个答案:

答案 0 :(得分:10)

您使用newArray,其类型为ST s (STArray s (Int, Int) Int)。但是,您在main函数的正文中使用它,这意味着您do必须具有IO类型的所有内容。 ST不是IO,因此类型无法匹配。

您应首先将newArray移动到您有权访问ST monad的上下文中。这个上下文当然可以在runSTArray的正文中找到,因此请将正文更改为:

    runSTArray $ do
        arr <- newArray ((0,0), (5,5)) 0 :: ST s (STArray s (Int, Int) Int)
        par (writeArray arr (1,1) 17) (writeArray arr (2,2) 23)
        return arr

然后,您需要重新考虑par的行为方式。 par用于创建并行计算,不能用于monadic操作; monad一般不能并行化。特别是,ST monad甚至没有为并行计算提供任何替代方案;因为并行写入数组会导致竞争条件(如果你覆盖同一个单元会发生什么?哪个写入会计数,哪个不会?),这里允许并行是不安全的。您必须按顺序更改数组:

    runSTArray $ do
        arr <- newArray ((0,0), (5,5)) 0 :: ST s (STArray s (Int, Int) Int)
        writeArray arr (1,1) 17
        writeArray arr (2,2) 23
        return arr

但是,写入并不昂贵;这是可能很昂贵的价值计算。假设您想要动态计算1723;然后,您可以执行以下操作:

let a = someLongCalculation 12534
    b = a `par` (someLongCalculation 24889)
writeArray arr (1, 1) a
writeArray arr (2, 2) b

最后,你必须意识到runSTArray返回结果数组,所以你必须像这样存储它:

import Control.Monad
import Control.Monad.ST
import Control.Parallel
import Data.Array.ST

main =
  let pureArr =
        runSTArray $ do
          arr <- newArray ((0,0), (5,5)) 0 :: ST s (STArray s (Int, Int) Int)
          writeArray arr (1,1) 17
          writeArray arr (2,2) 23
          return arr
  in print pureArr

我不认为STArray是正确的解决方案。在需要并行对称数组计算的情况下,应该使用更强大的数组库,如repa

答案 1 :(得分:1)

par用于并行编写纯操作。你正在撰写有效的运作。你不能使用标准杆。此外,并行性一种效果(至少在用变异组成时),并且在ST monad中不可用。我无法就构建代码的正确方法给出建议,因为事情太过简单,无法确定您的实际问题域是什么。但是,我的一般建议是,使用显式并发结构(如IO monad)来使用纯操作而不是mutatey数组。