必须用共享内存映射实现零拷贝:Array/Value不支持NumPy,Pool.map会因pickle导致内存暴涨;shared_memory或posix_ipc配合ndarray buffer可共享,但需手动管理shape/dtype/同步与释放。

直接用 Array 或 Value 无法高效共享大型 NumPy 数组——它们只支持 ctypes 基础类型,不兼容 NumPy 的内存布局和 dtype 元信息。真正在多进程间零拷贝共享大型数组,必须绕过 pickle 序列化,用底层共享内存映射。
为什么 multiprocessing.Pool(map) 会让大数组内存暴涨
当你把一个含 np.ndarray 的类实例传给 Pool.map(),Python 会强制 pickle 整个对象。哪怕函数只读取 arr[0],整个数组也会被序列化、传输、反序列化到每个子进程内存中。
- 若开 8 个 worker,内存占用 ≈ 8 × 数组原始大小 + 进程基础开销
-
Pool默认预取(prefetch)还会额外缓存返回值,峰值可能冲到 3× - 这不是 bug,是 fork/spawn 模型的必然行为
用 multiprocessing.shared_memory 实现 NumPy 零拷贝共享
SharedMemory 提供裸内存块,配合 np.ndarray 的 buffer 构造器,可让多个进程直接操作同一物理内存。关键点:你得自己管理 shape/dtype/size,并确保同步。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 主进程创建
SharedMemory,大小按arr.nbytes分配 - 用
np.ndarray(shape, dtype, buffer=shared_mem.buf)构造视图,不复制数据 - 子进程通过名称(
shared_mem.name)连接同一块内存,再构造自己的视图 - 必须用
Lock或信号量保护写操作,否则竞态导致脏数据
import numpy as np import multiprocessing as mp from multiprocessing import shared_memory import time <p>def worker(name, shape, dtype): existing_shm = shared_memory.SharedMemory(name=name) arr = np.ndarray(shape, dtype=dtype, buffer=existing_shm.buf)</p><h1>示例:只修改前100个元素</h1><pre class='brush:python;toolbar:false;'>arr[:100] *= 2 existing_shm.close()
if name == "main": big_arr = np.random.rand(10000, 1000).astype(np.float64) # ~800MB shm = shared_memory.SharedMemory(create=True, size=big_arr.nbytes) shared_arr = np.ndarray(big_arr.shape, dtype=big_arr.dtype, buffer=shm.buf) shared_arr[:] = big_arr[:] # 复制初始数据(仅一次)
p = mp.Process(target=worker, args=(shm.name, big_arr.shape, big_arr.dtype)) p.start() p.join() print(shared_arr[0, :5]) # 已被修改 shm.close() shm.unlink() # 删除共享内存(注意:必须由创建者调用)
posix_ipc + mmap 是更可控的替代方案
当 shared_memory 在某些旧系统或容器环境不可用时,posix_ipc 提供更底层、跨 Python 版本兼容的 POSIX 共享内存控制能力。
立即学习“Python免费学习笔记(深入)”;
-
pip install posix_ipc后,用posix_ipc.SharedMemory("/myarr", size=N)创建 - 再用
mmap.mmap(fd, size)映射,然后传给np.ndarray(..., buffer=mapped) - 优势:显式控制生命周期、支持权限设置、便于调试(
ipcs -m查看) - 坑点:名称必须以
/开头;Windows 不原生支持(需 WSL 或 Cygwin)
真正难的不是“怎么共享”,而是“谁负责释放”和“读写边界是否对齐”。共享内存本身不带结构,shape/dtype/offset 全靠进程间约定——一旦错位,np.ndarray 视图就会越界或解码失败,且无运行时提示。

















