shared_memory比multiprocessing.array更适合大型数组,因其基于系统共享内存映射、零拷贝、容量大且可跨进程动态访问;但需手动管理同步、清理及dtype/shape传递。

shared_memory 为什么比 multiprocessing.Array 更适合大型数组?
因为 multiprocessing.Array 底层用的是 pickle + fork 时拷贝,数组越大,fork 开销越明显,且无法跨进程动态调整大小;而 shared_memory 直接映射系统共享内存段(POSIX 或 Windows 共享对象),读写零拷贝,容量上限取决于系统 shmmax 设置,适合 GB 级 ndarray。
但要注意:它不自动管理同步,也不封装锁,纯裸内存 —— 你得自己确保读写不冲突。
创建和连接 shared_memory 的正确姿势
关键不是“怎么建”,而是“谁建、谁连、谁清理”。常见错误是子进程重复调用 SharedMemory 构造函数试图新建同名块,结果报 FileExistsError;或者主进程退出后没调用 .close() 和 .unlink(),导致内存泄漏(ipcs -m 可查残留)。
- 主进程负责创建:
shm = SharedMemory(create=True, size=arr.nbytes, name="my_array") - 子进程必须用相同
name连接:shm = SharedMemory(name="my_array")(不能带create=True) - 所有进程用完后调用
shm.close();仅由创建者调用shm.unlink()(否则其他进程再访问会报FileNotFoundError)
把 numpy 数组映射到 shared_memory 的三步实操
numpy 本身不直接支持 shared_memory,必须手动构造 memoryview 再转成 ndarray。容易踩坑的是 dtype 和 shape 信息不随内存一起传递 —— 它们只存在 Python 对象里,不会进共享内存。
所以你要额外通过其他方式(如 multiprocessing.Queue、文件、或约定参数)把 dtype 和 shape 传给子进程。
- 主进程写入:
import numpy as np from multiprocessing import shared_memory <p>arr = np.random.rand(10000, 1000) # ~80MB shm = shared_memory.SharedMemory(create=True, size=arr.nbytes, name="big_data") shared_arr = np.ndarray(arr.shape, dtype=arr.dtype, buffer=shm.buf) shared_arr[:] = arr[:] # 复制数据</p>
- 子进程读取:
shm = shared_memory.SharedMemory(name="big_data") # 必须知道 shape 和 dtype —— 这里硬编码,实际应传参 shared_arr = np.ndarray((10000, 1000), dtype=np.float64, buffer=shm.buf) # 此时 shared_arr 是只读视图(除非你明确加 write=True) # 若需写入,确保主进程未释放 shm.buf 且无竞态
多进程写入 shared_memory 的安全边界在哪?
shared_memory 本身不提供原子操作或锁机制。如果你让多个进程同时往同一块内存写(比如累加),大概率得到错误结果 —— 这不是 Python GIL 的问题,而是 CPU 缓存行竞争和非原子写导致的。
真正能用的方案只有两种:
- 严格分工:一个进程写,多个进程读(最常用,也最安全)
- 配合
multiprocessing.Semaphore或multiprocessing.Lock控制写区域,但注意 lock 对象本身不能放在 shared_memory 里,必须单独创建并传入 - 避免用
np.ndarray直接赋值大块区域(如a[:] = b),底层是循环 memcpy,中间断开会导致部分写入;改用np.copyto(dst, src)更可控
跨进程修改单个标量(比如计数器)也得加锁,别信“int 赋值是原子的” —— 在多核下不成立。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











