假设我有一个大的内存numpy数组,我有一个函数func,它接受这个巨大的数组作为输入(以及一些其他参数)func可以并行运行。例如:
定义函数(arr,param):
#做点什么吧,波拉姆
#构建阵列arr
池=池(进程=6)
结果=[pool.apply_async(func[arr,param]),用于所有_参数中的参数]
输出=[res.get()用于res in results]
若我使用多处理库,那个么这个巨大的数组将被多次复制到不同的进程中
有没有办法让不同的进程共享同一个数组?此数组对象是只读的,永远不会被修改
更复杂的是,如果arr不是一个数组,而是一个任意的python对象,有没有办法共享它
[已编辑]
我读了答案,但还是有点困惑。因为fork()是写时复制的,所以在python多处理库中生成新进程时,我们不应该调用任何额外的开销。但以下代码表明存在巨大的开销:
来自多处理导入池管理器的
输入numpy作为np;
导入时间
def f(arr):
返回长度(arr)
t=time.time()
arr=np.arange(10000000)
打印“construct array=,time.time()-t;
池=池(进程=6)
t=time.time()
res=pool.apply_async(f,[arr,])
res.get()
打印“多处理开销=”,time.time()-t;
输出(顺便说一下,成本随着阵列大小的增加而增加,因此我怀疑仍然存在与内存复制相关的开销):
construct array=0.0178790092468
多处理开销=0.252444982529
如果我们不复制阵列,为什么会有如此巨大的开销?共享内存为我节省了什么
如果您使用的操作系统使用写时复制fork()语义(与任何常见的unix一样),那么只要您从不更改数据结构,所有子进程都可以使用它,而不会占用额外的内存。您不必做任何特殊的事情(除非绝对确保不更改对象)
您能为您的问题做的最有效的就是将您的数组打包成一个有效的数组结构(使用numpy或array),将其放入共享内存中,用多处理.array将其打包,并将其传递给您的函数。这个答案说明了如何做到这一点
如果您想要一个可写的共享对象,那么您需要用某种同步或锁定来包装它多处理提供了两种方法:一种是使用共享内存(适用于简单值、数组或cType)或管理器代理,其中一个进程持有内存,管理器仲裁其他进程(甚至通过网络)对内存的访问
Manager方法可以用于任意Python对象,但比使用共享内存的等效方法要慢,因为对象需要序列化/反序列化并在进程之间发送
Python中有大量可用的并行处理库和方法多处理是一个优秀且全面的库,但如果您有特殊需要,也许其他方法之一可能会更好