写入共享内存制作副本?

时间:2018-02-24 06:19:31

标签: python numpy parallel-processing shared-memory python-multiprocessing

我正在尝试并行化一个程序,该程序使用共享内存在网络上读取分块的numpy数组。它似乎工作(我的数据来自另一边),但我所有子进程的内存大约达到共享内存的大小(每个大约100-250MB),当我写入它时就会发生这种情况。有没有办法避免创建这些副本?它们似乎是不必要的,因为数据传播回实际的共享内存阵列。

以下是我使用posix_ipc,mmap和numpy(np)设置数组的方法:

shared = posix_ipc.SharedMemory(vol.uuid, flags=O_CREAT, size=int(nbytes))
array_like = mmap.mmap(shared.fd, shared.size)
renderbuffer = np.ndarray(buffer=array_like, dtype=vol.dtype, shape=mcshape)

执行此操作时内存会增加:

renderbuffer[ startx:endx, starty:endy, startz:endz, : ] = 1

感谢您的帮助!

1 个答案:

答案 0 :(得分:3)

您的实际数据有4个维度,但我将通过一个更简单的2D示例。

想象一下,你有这个数组(renderbuffer):

  1   2   3   4   5
  6   7   8   9  10
 11  12  13  14  15
 16  17  18  19  20

现在假设你的startx / endx / starty / endy参数在一个进程中选择这个切片:

  8   9
 13  14
 18  19

整个数组是8x字节的4x5倍,因此是160字节。 “窗口”是8个字节的3x2倍,因此是48个字节。

您的期望似乎是访问此48字节切片在此过程中需要48个字节的内存。但实际上它需要更接近完整的160个字节。为什么呢?

原因是内存映射在页面中,每个页面通常为4096字节。因此,当您访问第一个元素(此处为数字8)时,您将映射包含该元素的整个页面4096个字节。

许多系统上的内存映射保证在页面边界上开始,因此数组中的第一个元素将位于页面的开头。因此,如果您的数组是4096字节或更小,访问它的任何元素将在每个进程中将整个数组映射到内存。

在您的实际用例中,您在切片中访问的每个元素都将导致映射包含它的整个页面。内存中相邻的元素(意味着切片中的第一个或最后一个索引递增1,具体取决于您的数组order)通常位于同一页面中,但在其他维度中相邻的元素可能位于单独的页面。

但请记住:内存映射是在进程之间共享的,所以如果整个数组都是200 MB,即使每个进程最终映射大部分或全部,所有进程的总内存使用量仍然是200 MB 。许多内存测量工具将报告每个进程使用200 MB,这是真实但无用的:它们共享相同内存的200 MB视图。