如何在工作进程中对SharedArray使用Interpolations,而不是每个进程都创建自己的数据副本?

时间:2016-07-29 16:03:51

标签: interpolation julia shared-memory

我正在使用64位Debian Stretch中的Julia 0.4.6(“测试”)。我目前正在4核4Gbyte VM中使用它。

我基本上要做的是让主进程设置3D SharedArray,然后在工作进程上并行化从该3D数组派生的2D数组的生成。问题是,如果我希望工作人员通过插值访问该卷(所有这些,因为我无法预测他们实际需要哪些位),我似乎遇到了大量内存使用问题。

这是一些最小的代码,展示了我正在尝试做的事情......

首先是一个插值免费版本:

# Initialize 1GByte of SharedArray
volume=SharedArray(Float32,(512,512,1024))  # 1 GByte of shared data
volume[:,:,:]=rand(Float32,(512,512,1024))

# Function to compute directly from array
function test0()
  image=SharedArray(Float32,(512,512))
  @sync @parallel for y=1:512
    for x=1:512
      image[x,y]=volume[x,y,512]
    end
  end
  sdata(image)
end

println(mean(test0()))

无论我是在没有工作人员还是-p 2,-p 4,-p 8或-p 16的情况下运行它都没有问题(性能没有太大改善,但请记住这只是一个模型在每次迭代中做更多的计算)。

但是这个版本:

using Interpolations

# Function to compute via interpolator
function test1()
  sampler=interpolate(volume,BSpline(Linear()),OnGrid())

  image=SharedArray(Float32,(512,512))

  @sync @parallel for i=1:512*512
    x,y=ind2sub((512,512),i)
    image[x,y]=sampler[x,y,512]
  end
  sdata(image)
end

println(mean(test1()))

使用-p 2启动系统交换,-p 4使工作人员以OutOfMemoryError s终止。

我正在猜测是内插器到工作进程的序列化会忽略它位于SharedArray上的事实,只是将数据批量复制到非共享副本中每个工人。

我的问题是:我该怎么做才能改善这一点?是否有一个更好的模式,我正在尝试做什么,或一些狡猾的使用@<something>,这将导致每个工作人员插入共享数组而不是它自己的副本?

更新

这种方法似乎有效地将插值对象的创建推送到每个工作进程中:

function test(volume)

  image=SharedArray(Float32,(512,512))

  sampler=Nullable()

  @sync @parallel for i=1:512*512
    x,y=ind2sub((512,512),i)
    if isnull(sampler)
      warn(STDERR,"Allocating sampler...")
      sampler=Nullable(Interpolations.interpolate(sdata(volume),Interpolations.BSpline(Interpolations.Linear()),Interpolations.OnGrid()))
      warn(STDERR,"...allocated sampler")
    end
    image[x,y]=get(sampler)[x,y,512]
  end
  sdata(image)
end

...但是它仍然遇到完全相同的问题,并且由于内存耗尽,不止一些工作进程将开始交换或无法创建采样器。

仔细检查Interpolations.jl代码表明它通常希望对给定的数组进行填充和/或预过滤(这显然意味着它需要复制)...但是我还不能很好地阅读Julia足以理解BSpline(Linear())是否有机会绕过正在制作的副本,并避免大量的每进程内存开销。我看到二次插值提供了一个有趣的预过滤选项“InPlace”,但我还没有进一步探讨(一个重要的问题似乎是避免所有工作人员试图预先过滤共享数据)。

1 个答案:

答案 0 :(得分:2)

Apparently解决方案是使用interpolate!版本的插值。这与我投入的工作流程一样好用:

using Interpolations

# Function to compute via interpolator
function test(volume)

  image=SharedArray(Float32,(512,512))

  sampler=interpolate!(
    volume,
    Interpolations.BSpline(Interpolations.Linear()),
    Interpolations.OnGrid()
  )

  @sync @parallel for i=1:512*512
    x,y=ind2sub((512,512),i)
    image[x,y]=sampler[x,y,512]
  end
  sdata(image)
end

# Initialize 1GByte of SharedArray
volume=SharedArray(Float32,(512,512,1024))  # 1 GByte of shared data
volume[:,:,:]=rand(Float32,(512,512,1024))

println(mean(test(volume)))

还有一个prefilter!暗示也可以类似地使用高阶插值方法,但线性插值对于我的目的来说足够好。