Python3中pool.apply_async配合multiprocessing.Array与Process结果不同原因
问题原因
- Pool传参强制序列化:
Pool.apply_async传递参数时,必须经过pickle序列化再传输到子进程,子进程反序列化后得到的提前转换好的numpy数组是深拷贝,不再绑定原始的共享内存缓冲区,修改操作只会作用在拷贝数组上,不会影响父进程的共享内存。 - Linux下Process启动走fork逻辑:Linux系统默认使用fork模式启动子进程,fork会直接继承父进程的整个地址空间,不需要对参数做序列化,此时传递的numpy数组仍指向原来的共享内存地址,所以修改可以直接生效。
- 跨平台差异:Windows系统没有fork系统调用,所有multiprocessing启动的子进程都走spawn模式,所有参数必须序列化,所以你提供的测试代码在Windows下不管用Process还是Pool都无法修改共享内存,和你贴的运行结果完全吻合。
修复方案
核心逻辑是:不要在父进程提前将Array转为numpy数组再传参,直接传递Array共享对象本身,在子进程内部再做numpy数组转换。Array对象本身支持pickle序列化,序列化/反序列化后仍会指向同一块系统级共享内存,不会产生数据拷贝。
修改后的可运行代码如下:
from multiprocessing import Process, Array, Pool import numpy as np from ctypes import c_ubyte def f(shared_arr): # 子进程内完成共享内存到numpy数组的转换 a = np.frombuffer(shared_arr, dtype=np.uint8) print(id(a)) a[1] = np.uint8(255) return 0 if __name__ == '__main__': a = Array(c_ubyte, np.zeros((4,), dtype=np.uint8), lock=False) a_ = np.frombuffer(a, dtype=np.uint8) print(id(a_)) pool = Pool(2) res = pool.apply_async(f, (a,)) pool.close() pool.join() print("after pool") print('a:', a[:]) p = Process(target=f, args=(a,)) p.start() p.join() print("after Process") print('a:', a[:])
修改后Linux环境下Pool和Process的运行效果完全一致,都可以正确修改共享内存内容,Windows环境下两种调用方式也都能正常修改共享内存。
内容的提问来源于stack exchange,提问作者Uesugi Erii
相关产品推荐
相关产品推荐

