如何克服python多处理中的开销?

2024-04-20 10:19:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我在获取python中多处理的好处方面遇到了问题。基本上,每增加一个额外的核,计算时间就会增加。所以我的猜测是,这是由于开销,但我不确定我到底做错了什么,以及如何改进/克服它。我真正的问题有点复杂,但我准备了一个简单的例子来说明我的问题

简要说明:

我有一个相互独立的对象列表。对于每个对象,我需要调用一个函数,该函数将其他对象的字典作为输入。然后对初始列表中的每个对象进行多次计算。所以它基本上是一个循环中的一个循环

下面是一段代码,其中包含问题的一个非常简化的版本

import time
import multiprocessing as mp
import numpy as np

def test_fun(iter_nr, mp_dict, i, return_dict):
    dumm = 0
    for j in range(iter_nr):
        
        for val in mp_dict.values():
            dumm += val
            
    return_dict[i] = dumm

    
manager = mp.Manager()
return_dict = manager.dict()
mp_dict = manager.dict()
for i in range(100):
    mp_dict[str(i)] = 1
    

nproc = [2,4,6,8,10,12,16,20]
nr_iter = 2*4*6*8*10
jobs = []

print('Total number of iterations: ', nr_iter)

if __name__ == '__main__':
    
    for n_proc in nproc:
        
        nr_iter_array = (nr_iter / n_proc ) * np.ones(n_proc)

        print('Nr CPUs: ', n_proc)
        print('Nr iterations per process: ', int(nr_iter_array[0]))

        start_time = time.time()

        for i in range(n_proc):

            p = mp.Process(target = test_fun, args = (int(nr_iter_array[i]), mp_dict, i, return_dict))
            p.start()
            jobs += [p]

        for job in jobs:
            job.join()

        end_time = time.time()
        print(round(end_time - start_time, 3), 'sec')

这是输出

Total number of iterations:  3840
Nr CPUs:  2
Nr iterations per process:  1920
0.661 sec
Nr CPUs:  4
Nr iterations per process:  960
1.385 sec
Nr CPUs:  6
Nr iterations per process:  640
1.674 sec
Nr CPUs:  8
Nr iterations per process:  480
1.524 sec
Nr CPUs:  10
Nr iterations per process:  384
1.992 sec
Nr CPUs:  12
Nr iterations per process:  320
2.072 sec
Nr CPUs:  16
Nr iterations per process:  240
2.186 sec
Nr CPUs:  20
Nr iterations per process:  192
2.607 sec

如您所见,计算时间随着核数的增加而增加。这不是我所期望的。有人知道这里发生了什么,以及如何克服这一点吗


1条回答
网友
1楼 · 发布于 2024-04-20 10:19:53

这是进程创建开销的一种情况。您的任务太小,无法从多处理中获益

当我运行你的代码时,我得到了与你相同的结果。然而,当我开始调整时

for i in range(100):
    mp_dict[str(i)] = 1

这一部分将范围更改为1000,有一些多处理的好处(我在一台内核数量有限的笔记本电脑上运行,您的结果可能会有所不同)

Total number of iterations:  3840
Nr CPUs:  2
Nr iterations per process:  1920
0.237 sec
Nr CPUs:  4
Nr iterations per process:  960
0.216 sec
Nr CPUs:  6
Nr iterations per process:  640
0.221 sec
Nr CPUs:  8
Nr iterations per process:  480
0.224 sec
Nr CPUs:  10
Nr iterations per process:  384
0.233 sec
Nr CPUs:  12
Nr iterations per process:  320
0.231 sec
Nr CPUs:  16
Nr iterations per process:  240
0.243 sec
Nr CPUs:  20
Nr iterations per process:  192
0.255 sec

当我把它改为10000时,改进的结果又出现了

Total number of iterations:  3840
Nr CPUs:  2
Nr iterations per process:  1920
1.578 sec
Nr CPUs:  4
Nr iterations per process:  960
1.063 sec
Nr CPUs:  6
Nr iterations per process:  640
1.076 sec
Nr CPUs:  8
Nr iterations per process:  480
1.083 sec
Nr CPUs:  10
Nr iterations per process:  384
1.098 sec
Nr CPUs:  12
Nr iterations per process:  320
1.08 sec
Nr CPUs:  16
Nr iterations per process:  240
1.099 sec
Nr CPUs:  20
Nr iterations per process:  192
1.122 sec

我没有尝试过的一个调整,但可能会再次改变数字,就是用多处理的池替换您的自管理进程。这个例子很可能适用于一个池。一个人才库只启动N个流程一次,然后继续利用这些流程,并在员工有空时向其发送更多工作。您可以生成和杀死很多进程,而池只能生成和杀死一次

不过,这并不是一种神奇的治疗方法。我最喜欢的多处理问题是数据传输。多处理和池在非常慢的队列中执行此操作。管理者使用相同的队列,速度也很慢。您向员工发送或从员工发送的数据越多,您在这方面花费的时间就越多。通常,更好的做法是重新设计代码,使其在工作人员中完成从开始到结束的任务,而不是发送大量的输入/输出

总之,结论是这取决于你的情况。多处理并不总是能提高性能,即使能提高性能,改进也可能是适度的。它需要一点评估,就像你所做的那样,以找出最佳位置

这是一个有点不回答,但它是太长的评论

相关问题 更多 >