我正在尝试并行化一个程序,该程序使用共享内存在网络上读取分块的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
感谢您的帮助!
答案 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视图。