Python multiprocessing Pool搭配shared_memory使用的相关问题咨询
基础概念解答
memory view是不是指针?
不是C语言层面的原生指针,它是Python对缓冲区协议的封装,作用是允许你直接访问对象的底层内存数据,不需要做全量内存拷贝。SharedMemory的buf属性就是指向共享内存块的memory view,直接作为numpy数组的buffer参数传入,就能让numpy数组直接使用共享内存作为数据存储,没有额外拷贝开销。
关于Python对象跨进程共享的猜想是否正确?
你的猜想基本成立:numpy数组c是进程内的Python对象,本身无法跨进程直接使用。不过这和GIL无关,GIL是单个进程内多线程的全局解释器锁,跨进程时每个进程有完全独立的地址空间,不管有没有GIL,进程内的Python对象都不能直接被其他进程访问。只有共享内存块本身是跨所有进程可见的,你需要在每个进程中单独创建numpy数组来包装同一块共享内存。
你代码报错的核心原因
- 你使用了全局变量
existing_shm、a,在Windows、macOS默认的spawn进程启动模式下,子进程不会继承主进程的全局变量,运行时会直接报NameError。 - 没有把共享内存的名称、数组形状、数据类型等必要参数传递给子进程的工作函数,子进程无法自行打开共享内存。
- 主进程没有把原始数组的数据拷贝到共享内存中,初始状态下共享内存是无意义的随机值。
- 没有做共享内存的释放操作,会造成系统内存泄漏。
修正后的可运行代码
首先导入依赖:
import os import numpy as np from multiprocessing import Pool, shared_memory
工作函数不能依赖全局变量,所有必要参数通过传参获取:
def test_function(args): shm_name, arr_shape, arr_dtype = args # 子进程内单独打开共享内存 current_shm = shared_memory.SharedMemory(name=shm_name) # 子进程内单独创建numpy数组包装共享内存,无额外内存拷贝 c = np.ndarray(arr_shape, dtype=arr_dtype, buffer=current_shm.buf) c[1] = 100 print(c) # 关闭当前进程的共享内存连接 current_shm.close()
主逻辑必须放在if __name__ == '__main__'块中,这是multiprocessing模块的强制要求,避免spawn模式下无限递归创建子进程:
if __name__ == '__main__': # 原始数组,明确指定dtype避免后续类型不匹配 original_arr = np.array([1, 1, 2, 3, 5, 8], dtype=np.int64) # 创建共享内存 shm = shared_memory.SharedMemory(create=True, size=original_arr.nbytes) # 主进程先把原始数组数据拷贝到共享内存中 main_shm_arr = np.ndarray(original_arr.shape, dtype=original_arr.dtype, buffer=shm.buf) main_shm_arr[:] = original_arr[:] # 构造传给每个子进程的参数 task_params = [(shm.name, original_arr.shape, original_arr.dtype) for _ in range(12)] with Pool(os.cpu_count()) as pool: pool.map(test_function, task_params) # 所有任务执行完成后,主进程关闭并销毁共享内存 shm.close() shm.unlink()
常见疑问明确
- 主进程创建
shm后不需要额外创建existing_shm实例,直接使用shm即可。 - 每个进程必须单独创建自己的numpy数组对象包装共享内存,这个操作开销极低,不会额外复制数据,只是创建了一个指向共享内存的Python包装对象。
- 所有多进程相关的主逻辑必须放在
if __name__ == '__main__'块中,否则在非fork模式的系统上会直接报错。
内容的提问来源于stack exchange,提问作者aerijman
相关产品推荐
相关产品推荐

