首页 > 解决方案 > 对于多处理星图来说,这种加速正常吗?

问题描述

代码:

from multiprocessing import Pool
from itertools import repeat
import timeit
import multiprocessing

def add_one(number, flag):

    new_number = None
    if flag=="a":
        new_number = number+1

    return (number, new_number)

numbers = list(range(10000000))
pool = Pool(multiprocessing.cpu_count())

for i in range(3):
    print(i)
    start_time = timeit.default_timer()
    flag = "a"
    new_numbers = pool.starmap(add_one, zip(numbers, repeat(flag)))
    print('time taken: ', timeit.default_timer() - start_time)

池计数配置分别为 3、1 和 multiprocessing.cpu_count()。他们花费的时间如下:

(base) ins-MacBook-Pro-2 graph_test % python test.py
0
time taken:  7.543301321
1
time taken:  7.8004514
2
time taken:  7.892797112
ins-MacBook-Pro-2 graph_test % python test.py
0
time taken:  11.030308790000001
1
time taken:  11.616422934
2
time taken:  11.846459496999998
ins-MacBook-Pro-2 graph_test % python test.py
0
time taken:  6.376773281
1
time taken:  6.876658618999999
2
time taken:  6.518348029

我的 Mac 有 8 个内核。好像没有加速很多。我使用星图的方式正确吗?

标签: pythonmultithreading

解决方案


multiprocessing对于细粒度的并行性不会产生显着的加速 - 你需要做“大(ger)工作”,因为它在挂钟时间得到回报。

与使用多处理的开销add_one()相比,调用函数完成的工作简直是微不足道。在幕后,主程序必须挑选参数,通过进程间通信机制发送这些字符串;然后工人必须解开论点;然后该函数会做少量工作来比较一个字符串,并可能将 1 加到一个整数上,然后构建一个 2 元组的结果;然后多处理机器必须再次在幕后腌制那个 2 元组;通过进程间通信机制将pickle发送回主程序;然后主程序必须解开结果字符串,并将生成的 2 元组附加到列表中。"a"

您“看到”支持所有这一切的工作很少,但总的来说,支持工作的成本远远超过调用的成本add_one()

要查看与使用的内核数量更一致的加速,add_one()需要单独花费更多时间,因此并行工作的潜力更大。例如,更改:

if flag=="a":

if (flag * 100000)[0] =="a":

不,这不是一个明智的改变。这只是一种add_one()消耗更多时间的方法,因此您可以看到添加内核确实有帮助。它根本不会改变开销,它只会增加在多处理实现之外需要完成的工作量。制作所有这些无用的“大字符串”可以并且将会并行完成。

注意:不要将“核心”误认为“物理 CPU”。.cpu_count()通常返回“逻辑”(非物理)核心的数量。对于多处理,物理内核的数量通常更为重要。


推荐阅读