假设我有一个大内存numpy数组,我有一个函数 func
,它接受这个巨大的数组作为输入(连同一些其他参数) . 具有不同参数的 func
可以并行运行 . 例如:
def func(arr, param):
# do stuff to arr, param
# build array arr
pool = Pool(processes = 6)
results = [pool.apply_async(func, [arr, param]) for param in all_params]
output = [res.get() for res in results]
如果我使用多处理库,那么这个巨型数组将被多次复制到不同的进程中 .
有没有办法让不同的进程共享同一个数组?此数组对象是只读的,永远不会被修改 .
更复杂的是,如果arr不是一个数组,而是一个任意的python对象,有没有办法分享它?
[EDITED]
我读了答案,但我仍然有点困惑 . 由于fork()是copy-on-write,因此在python多处理库中生成新进程时不应调用任何额外的成本 . 但是下面的代码表明存在巨大的开销:
from multiprocessing import Pool, Manager
import numpy as np;
import time
def f(arr):
return len(arr)
t = time.time()
arr = np.arange(10000000)
print "construct array = ", time.time() - t;
pool = Pool(processes = 6)
t = time.time()
res = pool.apply_async(f, [arr,])
res.get()
print "multiprocessing overhead = ", time.time() - t;
输出(顺便说一下,随着数组大小的增加,成本也会增加,所以我怀疑仍有与内存复制相关的开销):
construct array = 0.0178790092468
multiprocessing overhead = 0.252444982529
如果我们不复制数组,为什么会有这么大的开销?共享内存拯救了我的哪一部分?
2 回答
如果您使用的是使用copy-on-write
fork()
语义的操作系统(如任何常见的unix),那么只要您永远不会改变您的数据结构,它就可供所有子进程使用而不占用额外的内存 . 你不必做任何特别的事情(除了绝对确保你不改变对象) .The most efficient thing you can do for your problem 将您的数组打包成一个有效的数组结构(使用
numpy
或array),将其放在共享内存中,用multiprocessing.Array
包装,并将其传递给您的函数 . This answer shows how to do that .如果你想要一个可写的共享对象,那么你需要用某种同步或锁定来包装它 .
multiprocessing
提供two methods of doing this:一个使用共享内存(适用于简单值,数组或ctypes)或Manager
代理,其中一个进程保存内存,管理器仲裁从其他进程(甚至通过网络)对它的访问 .Manager
方法可以与任意Python对象一起使用,但是比使用共享内存的等效方法慢,因为对象需要序列化/反序列化并在进程之间发送 .有一个wealth of parallel processing libraries and approaches available in Python .
multiprocessing
是一个优秀且全面的图书馆,但如果您有特殊需求,或许其他方法可能会更好 .我遇到了同样的问题,写了一个小的共享内存实用程序类来解决它 .
我正在使用multiprocessing.RawArray(lockfree),并且对数组的访问根本不同步(lockfree),小心不要自己动手 .
通过该解决方案,我在四核i7上获得了大约3倍的加速 .
这是代码:随意使用和改进它,请报告任何错误 .