因为multiprocessing.Array仅支持ctypes基本类型,无法承载NumPy的shape、dtype等元数据,传np.ndarray会触发pickle序列化导致完整拷贝;正确做法是用shared_memory创建共享内存块,主进程写入数据,子进程通过shm.name和相同dtype/shape重建ndarray视图,实现零拷贝。

为什么 multiprocessing.Array 不能直接共享 NumPy 数组
因为 multiprocessing.Array 只支持 ctypes 基本类型(如 c_double、c_int32),无法原生承载 NumPy 的元数据(shape、dtype、strides)。直接传 np.ndarray 会触发序列化(pickle),导致完整拷贝——这正是你要避免的。
真正可行的路径是:绕过 pickle,让多个进程映射同一块物理内存,并各自用 NumPy 的 np.frombuffer() 或 np.memmap() 构造视图。
- 必须显式创建共享内存块(如 POSIX 共享内存或匿名 mmap)
- NumPy 数组需用
dtype和shape重新解释该内存,不能依赖 pickle 重建 - 注意字节序和对齐,尤其跨平台时
用 shared_memory 模块(Python 3.8+)零拷贝共享
shared_memory 是标准库中唯一能安全跨进程共享原始字节缓冲区的方案。它底层调用 shm_open()(Unix)或 CreateFileMapping()(Windows),不经过 Python 对象层。
关键步骤:
立即学习“Python免费学习笔记(深入)”;
- 主进程创建
SharedMemory实例,大小 =arr.nbytes - 用
np.ndarray(..., buffer=shm.buf)构造视图(不是 copy) - 子进程通过名称(
shm.name)打开同一块内存,再用相同dtype和shape重建视图 - 务必手动调用
shm.close()和shm.unlink()(仅创建者调用 unlink)
示例核心片段:
from multiprocessing import shared_memory import numpy as np <h1>主进程</h1><p>arr = np.random.random((10000, 10000)).astype(np.float32) shm = shared_memory.SharedMemory(create=True, size=arr.nbytes) shared_arr = np.ndarray(arr.shape, dtype=arr.dtype, buffer=shm.buf) shared_arr[:] = arr[:] # 复制数据进共享内存</p><h1>子进程(需传入 shm.name 和 shape/dtype)</h1><p>existing_shm = shared_memory.SharedMemory(name=shm.name) shared_arr_ro = np.ndarray(arr.shape, dtype=arr.dtype, buffer=existing_shm.buf)</p><h1>此时 shared_arr_ro 与 shared_arr 指向同一物理内存
Windows 下常见报错:FileNotFoundError: [Errno 2] No such file or directory
这是 shared_memory 在 Windows 上的典型坑:它依赖系统临时目录下的文件模拟共享内存,但子进程可能无权访问该路径,或父进程未正确设置 inheritable=True。
- 确保使用
multiprocessing.get_context('spawn')启动子进程(Windows 默认是 spawn,但显式声明更稳) - 不要在子进程中直接 new
SharedMemory并传create=True—— 必须由父进程创建,子进程只attach - 检查
tempfile.gettempdir()路径权限;若受限,可设环境变量TEMP指向有写权限的目录 - Linux/macOS 无此问题,因直接使用
/dev/shm
替代方案:np.memmap + 文件锁(兼容旧 Python 版本)
当无法升级到 Python 3.8+,或需持久化共享时,np.memmap 是最稳妥的降级选择。它把数组映射到磁盘文件,多个进程可同时读写同一文件路径。
- 用
mode='r+'打开已有文件,避免覆盖 - 写入前加
threading.Lock不够——需进程级锁,推荐filelock库或fcntl.flock()(Unix)/mmap.mmap(..., access=mmap.ACCESS_WRITE)配合msync - 注意:SSD 寿命和 I/O 延迟,纯内存场景下性能不如
shared_memory - 文件路径必须绝对且所有进程可达(如 NFS 要小心缓存一致性)
简单示意:
# 创建 memmap 文件(一次)
np.memmap('shared.dat', dtype='float32', mode='w+', shape=(10000,10000))
<h1>所有进程都这样打开(不加 'w'!)</h1><p>arr = np.memmap('shared.dat', dtype='float32', mode='r+', shape=(10000,10000))共享内存本身不带同步语义,shape/dtype 错一位、忘记 close/unlink、Windows 权限路径、多进程同时写而无锁——这些才是实际落地时最常卡住的地方。


















