gpt4 book ai didi

python - 大型对象: How to achieve better parallel scaling in python?列表上多处理Pool.map()的缩放比例不佳

转载 作者:行者123 更新时间:2023-12-03 09:54:35 24 4
gpt4 key购买 nike

让我们定义:

from multiprocessing import Pool
import numpy as np
def func(x):
for i in range(1000):
i**2
return 1

请注意, func()会执行某些操作,并且始终返回少量的 1

然后,我比较一个8核并行 Pool.map() v/s一个串行,内置python的 map()
n=10**3
a=np.random.random(n).tolist()

with Pool(8) as p:
%timeit -r1 -n2 p.map(func,a)
%timeit -r1 -n2 list(map(func,a))

这给出了:
38.4 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
200 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)

显示了相当好的并行缩放。因为我使用8​​核,所以 38.3 [ms]大约是 200[s]的1/8

然后让我们在一些更大的列表上尝试 Pool.map(),为简单起见,我以这种方式使用列表列表:
n=10**3
m=10**4
a=np.random.random((n,m)).tolist()

with Pool(8) as p:
%timeit -r1 -n2 p.map(func,a)
%timeit -r1 -n2 list(map(func,a))

这使 :
292 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
209 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)

您会看到,并行缩放已不复存在! 1秒〜1.76秒

我们可以使情况变得更糟,尝试使每个子列表通过更大的范围:
n=10**3
m=10**5
a=np.random.random((n,m)).tolist()

with Pool(8) as p:
%timeit -r1 -n2 p.map(func,a)
%timeit -r1 -n2 list(map(func,a))

这给出了:
3.29 s ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)
179 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 2 loops each)

哇,子列表更大,计时结果完全相反。我们使用8核来使时序减慢20倍!!

您还可以注意到串行 map()的时间与子列表大小无关。因此,一个合理的解释是 Pool.map()确实将那些大子列表的内容传递给了引起额外复制的进程吗?

我不确定。但是如果是这样,为什么不通过子列表的地址呢?毕竟,子列表已经在内存中,实际上,我使用的 func()保证不会更改/修改子列表。

因此,在python中,将一些操作映射到大型对象列表上时,保持并行缩放的正确方法是什么?

最佳答案

您的工作职能过早结束:

In [2]: %timeit func(1)
335 µs ± 12.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

因此,您基本上是在衡量多处理的开销。

更改工作功能以执行更多工作,例如循环 1000 * 1000次而不是 1000次,您将看到它再次扩展, 1000000循环在我的mac上大致花费 0.4s,与开销相比足够高。

以下是我的Mac上不同 n的测试结果,我使用 Pool(4),因为我有4个内核,测试仅运行一次,而不是像 %timeit那样多次运行,导致差异不明显:

speedup graph

您会看到 speedup ration成比例地增加,每个工作函数调用都分担了多处理的开销。

后面的数学假设每个调用的开销是相等的:

ratio = {time_{single} \over time_{mp}} = {cost_{work} * n \over {{cost_{work} * n \over p_{cores}} + cost_{overhead} * n}} = {1 \over {\dfrac{1}{p_{cores}} + {cost_{overhead} \over cost_{work}} }}

如果我们想要 ratio > 1:

1 - {\dfrac{1}{p_{cores}} > {cost_{overhead} \over cost_{work}} }

大约等于:

enter image description here

这意味着,如果工作功能运行得太快,则与每次调用的开销相比, multiprocessing不会扩展。

关于python - 大型对象: How to achieve better parallel scaling in python?列表上多处理Pool.map()的缩放比例不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60128189/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com