haskell – 修复嵌套数组定义,导致“按顺序执行嵌套并行计算…”

作为一个更大问题的一部分,我试图在数组中定义一个数组,如下所示:

import Data.Array.Repa
type Arr = Array DIM2 Int

arr = force $fromList (Z :. 5 :. 5) [1..25] :: Arr

combined :: Arr
combined = arr `deepSeqArray` 
    traverse arr (\_ -> Z :. 4 :. 4 :: DIM2) (\f (Z :. x :. y) -> 
        let reg = force $extract f (x,y) (2,2)
        in  reg `deepSeqArray` sumAll reg)

extract :: (DIM2 -> Int) -> (Int,Int) -> (Int,Int) -> Arr
extract lookup (x0,y0) (width,height) = fromFunction bounds 
  $\sh -> offset lookup sh
    where 
    bounds = Z :. width :. height
    offset :: (DIM2 -> Int) -> DIM2 -> Int
    offset f (Z :. x :. y) = f (Z :. x + x0 :. y + y0)

main = print combined

提取函数使用fromFunction和提供给它的查找函数,但它也可以使用遍历和arr! ……为了同样的效果.尽管尽可能早地在所有地方使用force和deepSeqArray,但是控制台在这里填充了消息,然后是正确的结果:

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

虽然我没有构建一个带有列表来比较速度的版本,但在较大版本中,性能却受到了影响.

这只是嵌套数组定义的结果,因此我应该重构我的程序,将内部或外部定义作为列表?我的提取物功能是否可怕且问题的原因是什么?

提示from this question对于实现这一点非常有用,但我还没有浏览已编译的代码.

最佳答案 这是因为’print’也会隐式强制数组.内部’force’和’sumAll’函数调用并行计算,但是’print’,所以你有嵌套的并行性.这个非常明显的事实是在Repa 2 API中非常悲伤.

Repair 3通过导出’force’和’sumAll’等顺序和并行版本来解决这些问题.它还为数组类型添加了一个标记,以指示数组是延迟还是显示.维修3尚未完成,但您可以使用http://code.ouroborus.net/repa的头版本.在今年晚些时候的GHC 7.4之后它应该是短暂的.

这是您的示例的Repa 3版本,它运行时没有给出有关嵌套并行性的警告.请注意,’force’现在是’compute’.

import Data.Array.Repa

arr :: Array U DIM2 Int
arr = fromListUnboxed (Z :. 5 :. 5) [1..25]

combined :: Array U DIM2 Int
combined 
  = computeP $traverse arr (\_ -> Z :. 4 :. 4 :: DIM2) 
  $\f (Z :. x :. y) -> sumAllS $extract f (x,y) (2,2)

extract :: (DIM2 -> Int) -> (Int,Int) -> (Int,Int) -> Array D DIM2 Int
extract lookup (x0,y0) (width,height) 
  = fromFunction bounds 
  $\sh -> offset lookup sh
    where 
    bounds = Z :. width :. height
    offset :: (DIM2 -> Int) -> DIM2 -> Int
    offset f (Z :. x :. y) = f (Z :. x + x0 :. y + y0)

main = print combined
点赞