写入共享内存制作副本?

Writing to Shared Memory Making Copies?

我正在尝试并行化一个程序,该程序使用共享内存通过网络读取分块的 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

感谢您的帮助!

您的实际数据有 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 参数 select 这个切片在一个过程中:

  8   9
 13  14
 18  19

整个数组是 4x5 乘以 8 字节,所以 160 字节。 "window" 是 3x2 乘以 8 个字节,所以是 48 个字节。

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

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

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

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

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