Python:当使用块时,在多处理中实现负载平衡的最佳方法是什么

Python:当使用块时,在多处理中实现负载平衡的最佳方法是什么,python,multiprocessing,Python,Multiprocessing,例如,将17个任务分配给6块中的2个进程将是2*6+5,也就是说,每个进程得到6个任务,但剩余的5个任务。我认为最好的方法是将剩余的任务均匀地分布在2个进程中。所以我做了一个测试,看看mp.Pool是否是这样做的。下面是一个测试脚本 import multiprocessing as mp import time def f(x): time.sleep(0.1) print(mp.current_process()) if __name__ == "__main__":

例如,将17个任务分配给6块中的2个进程将是2*6+5,也就是说,每个进程得到6个任务,但剩余的5个任务。我认为最好的方法是将剩余的任务均匀地分布在2个进程中。所以我做了一个测试,看看mp.Pool是否是这样做的。下面是一个测试脚本

import multiprocessing as mp
import time
def f(x):
    time.sleep(0.1)
    print(mp.current_process())

if __name__ == "__main__":
    p = mp.Pool(2)
    p.map(f, range(17),6)
将输出

<ForkProcess(ForkPoolWorker-1, started daemon)>
<ForkProcess(ForkPoolWorker-2, started daemon)>
<ForkProcess(ForkPoolWorker-1, started daemon)>
<ForkProcess(ForkPoolWorker-2, started daemon)>
<ForkProcess(ForkPoolWorker-1, started daemon)>
<ForkProcess(ForkPoolWorker-2, started daemon)>
<ForkProcess(ForkPoolWorker-1, started daemon)>
<ForkProcess(ForkPoolWorker-2, started daemon)>
<ForkProcess(ForkPoolWorker-1, started daemon)>
<ForkProcess(ForkPoolWorker-2, started daemon)>
<ForkProcess(ForkPoolWorker-1, started daemon)>
<ForkProcess(ForkPoolWorker-2, started daemon)>
<ForkProcess(ForkPoolWorker-1, started daemon)>
<ForkProcess(ForkPoolWorker-1, started daemon)>
<ForkProcess(ForkPoolWorker-1, started daemon)>
<ForkProcess(ForkPoolWorker-1, started daemon)>
<ForkProcess(ForkPoolWorker-1, started daemon)>

请注意最后5行,很明显,剩余的任务都分配给一个进程,而其他所有进程则无事可做


有没有一种好方法可以自动分配
Pool.map中的剩余块?

不需要简单的参数变化。并且,当进程已分配给工作进程时,也不会重新分配它们

当然,您可以编写一个变通方法:

if __name__ == "__main__":
    p = mp.Pool(2)
    tasks = 17
    chunksize = 6

    p.map(f, range((tasks / chunksize) * chunksize), 6)
    p.map(f, range((tasks / chunksize) * chunksize + 1, tasks))
这将首先执行完整的块。剩下的五个任务将被一个接一个地分配到池中,而不是分块分配。这将产生期望的结果

不过,我不知道这为什么重要。如果任务需要很长时间才能完成,那么使用块有什么意义?不会有任何绩效提升,因为时间会花在员工身上。默认块大小为1时,您会做得非常好,只要一个工人有空,您就可以将任务分配给他

如果任务在很短的时间内完成,并且将花费更多的时间逐个向工作人员传输数据,Chunksize可以提高性能。如果是这样的话,那么最后的任务是否只由一名工人完成并不重要,因为完成这几项任务的时间微不足道

这个特别的例子当然是最坏的情况。在更现实的场景中,通常不会出现任何性能损失。想象一下,一批数万个任务以35个为单位发送给工人。在批处理过程中,工人不可避免地会出现分歧,他们不能完全在同一时间完成工作。有些块会更快,有些会更慢。现在让我们假设你的余数不是34而是17。如果worker A现在已开始最后一个完整区块,并且在worker B完成最后一个完整区块并获得剩余的17个区块时处理了不到一半的任务,则worker B很可能在worker A之前实际完成,尽管已处理完剩余的集合


但是,如果有理由先做块,然后把剩余的分配给工人,那么这就是方法。我确实认为您正在尝试解决一个不是问题的问题,但是,为了难以衡量的性能增益,您只会增加代码的复杂性

不是简单的参数变化。并且,当进程已分配给工作进程时,也不会重新分配它们

当然,您可以编写一个变通方法:

if __name__ == "__main__":
    p = mp.Pool(2)
    tasks = 17
    chunksize = 6

    p.map(f, range((tasks / chunksize) * chunksize), 6)
    p.map(f, range((tasks / chunksize) * chunksize + 1, tasks))
这将首先执行完整的块。剩下的五个任务将被一个接一个地分配到池中,而不是分块分配。这将产生期望的结果

不过,我不知道这为什么重要。如果任务需要很长时间才能完成,那么使用块有什么意义?不会有任何绩效提升,因为时间会花在员工身上。默认块大小为1时,您会做得非常好,只要一个工人有空,您就可以将任务分配给他

如果任务在很短的时间内完成,并且将花费更多的时间逐个向工作人员传输数据,Chunksize可以提高性能。如果是这样的话,那么最后的任务是否只由一名工人完成并不重要,因为完成这几项任务的时间微不足道

这个特别的例子当然是最坏的情况。在更现实的场景中,通常不会出现任何性能损失。想象一下,一批数万个任务以35个为单位发送给工人。在批处理过程中,工人不可避免地会出现分歧,他们不能完全在同一时间完成工作。有些块会更快,有些会更慢。现在让我们假设你的余数不是34而是17。如果worker A现在已开始最后一个完整区块,并且在worker B完成最后一个完整区块并获得剩余的17个区块时处理了不到一半的任务,则worker B很可能在worker A之前实际完成,尽管已处理完剩余的集合


但是,如果有理由先做块,然后把剩余的分配给工人,那么这就是方法。我确实认为您正在尝试解决一个不是问题的问题,但是,为了难以衡量的性能增益,您只会增加代码的复杂性

这是一个很好的答案,但我可能会把解决办法留到最后,因为这不是答案的主旨。非常感谢您耐心的解释+1这是一个很好的答案,但我可能会把解决办法留到最后,因为这不是答案的主旨。非常感谢您耐心的解释+1.