假设我有一个大的内存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对象,有没有办法共享它?
[编辑]
我读了答案,但还是有点困惑。由于fork()是写时复制,因此在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
如果我们不复制阵列,为什么会有这么大的开销?共享内存能帮我省下什么?
这是Ray的预期用例,它是一个用于并行和分布式Python的库。在引擎盖下,它使用Apache Arrow数据布局(零拷贝格式)序列化对象,并将它们存储在shared-memory object store中,以便多个进程可以访问它们,而无需创建副本。
代码如下所示。
如果不调用
ray.put
,那么数组仍将存储在共享内存中,但每次调用func
时都会调用一次,这不是您想要的。请注意,这不仅适用于数组,而且也适用于包含数组的对象,例如字典将int映射到数组,如下所示。
通过在IPython中运行以下命令,可以比较Ray和pickle中序列化的性能。
使用Ray的序列化只比pickle快一点,但由于使用了共享内存,反序列化的速度要快1000倍(这个数字当然取决于对象)。
请参阅Ray documentation。您可以阅读有关fast serialization using Ray and Arrow的更多信息。注意我是Ray的开发者之一。
我遇到了同样的问题,并编写了一个小的共享内存实用程序类来解决这个问题。
我使用的是
multiprocessing.RawArray
(lockfree),而且对数组的访问根本不同步(lockfree),小心别开枪打自己的脚。有了这个解决方案,我可以在四核i7上获得大约3倍的加速。
代码如下: 请随意使用和改进,并报告任何错误。
如果您使用的操作系统使用的是写时复制(copy-on-write)
fork()
语义(类似于任何常见的unix),那么只要您从不更改数据结构,它就可以在不占用额外内存的情况下供所有子进程使用。你不必做任何特别的事情(除非你绝对不要改变对象)。对于您的问题,您可以做的最有效的事情是将您的数组打包成一个有效的数组结构(使用} ),将其放在共享内存中,用
numpy
或^{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
是一个优秀且全面的库,但是如果您有特殊需要,其他方法之一可能更好。相关问题 更多 >
编程相关推荐