Python中的multiprocessing/pool.map与Chunksize无关?

7

我尝试使用Python的进程池多处理功能。

无论我如何设置块大小(在Windows 7和Ubuntu下 - 后者使用4个内核,见下文),并行线程的数量似乎保持不变。

from multiprocessing import Pool
from multiprocessing import cpu_count
import multiprocessing
import time


def f(x):
    print("ready to sleep", x, multiprocessing.current_process())
    time.sleep(20)
    print("slept with:", x, multiprocessing.current_process())


if __name__ == '__main__':
    processes = cpu_count()
    print('-' * 20)
    print('Utilizing %d cores' % processes)
    print('-' * 20)
    pool = Pool(processes)
    myList = []
    runner = 0
    while runner < 40:
        myList.append(runner)
        runner += 1
    print("len(myList):", len(myList))

    # chunksize = int(len(myList) / processes)
    # chunksize = processes
    chunksize = 1
    print("chunksize:", chunksize)
    pool.map(f, myList, 1)

无论我使用chunksize = int(len(myList) / processes)chunksize = processes还是1(如上面的例子),行为都是相同的。

可能自动将chunksize设置为核心数量吗?

chunksize = 1的示例:

--------------------
Utilizing 4 cores
--------------------
len(myList): 40
chunksize: 10
ready to sleep 0 <ForkProcess(ForkPoolWorker-1, started daemon)>
ready to sleep 1 <ForkProcess(ForkPoolWorker-2, started daemon)>
ready to sleep 2 <ForkProcess(ForkPoolWorker-3, started daemon)>
ready to sleep 3 <ForkProcess(ForkPoolWorker-4, started daemon)>
slept with: 0 <ForkProcess(ForkPoolWorker-1, started daemon)>
ready to sleep 4 <ForkProcess(ForkPoolWorker-1, started daemon)>
slept with: 1 <ForkProcess(ForkPoolWorker-2, started daemon)>
ready to sleep 5 <ForkProcess(ForkPoolWorker-2, started daemon)>
slept with: 2 <ForkProcess(ForkPoolWorker-3, started daemon)>
ready to sleep 6 <ForkProcess(ForkPoolWorker-3, started daemon)>
slept with: 3 <ForkProcess(ForkPoolWorker-4, started daemon)>
ready to sleep 7 <ForkProcess(ForkPoolWorker-4, started daemon)>
slept with: 4 <ForkProcess(ForkPoolWorker-1, started daemon)>
ready to sleep 8 <ForkProcess(ForkPoolWorker-1, started daemon)>
slept with: 5 <ForkProcess(ForkPoolWorker-2, started daemon)>
ready to sleep 9 <ForkProcess(ForkPoolWorker-2, started daemon)>
slept with: 6 <ForkProcess(ForkPoolWorker-3, started daemon)>
ready to sleep 10 <ForkProcess(ForkPoolWorker-3, started daemon)>
slept with: 7 <ForkProcess(ForkPoolWorker-4, started daemon)>
ready to sleep 11 <ForkProcess(ForkPoolWorker-4, started daemon)>
slept with: 8 <ForkProcess(ForkPoolWorker-1, started daemon)>

我感到困惑;为什么分块大小设置核心数量,而这又可以通过池大小以松散的方式进行配置呢? - roganjosh
也许这也是我提出问题的原因。至少文档(https://docs.python.org/3.6/library/multiprocessing.html#multiprocessing.pool.Pool.__init__)指出:“此方法将可迭代对象切成多个块,然后将其作为单独的任务提交到进程池中。可以通过将chunksize设置为正整数来指定这些块的(大致)大小。” - user9098935
2
这是指发送到每个进程的数据块有多大。我有一张披萨和4位客人。我是将披萨切成四份,给每位客人一大片,还是将其切成16块,让每位客人吃4块?两种决策都不会改变桌子上的客人数量,但它确实会改变他们需要拿新片的频率。 - roganjosh
1个回答

33

Chunksize不影响使用多少个核心,这由 Pool processes 参数设置。 Chunksize设置在你传递给 Pool.map 的可迭代项中,每个单个工作进程同时分配多少项,称为“任务”(下图显示了Python 3.7.1)。

task_python_3.7.1

如果将 chunksize = 1 ,则工作进程仅在完成之前接收到的一个任务后,才会获得一个新的任务。对于 chunksize> 1 ,工作程序会在一次任务中一次性获得整个批量的项目,并且在完成时,如果还有剩余,则会获得下一批。

使用 chunksize = 1 逐个分发项目可以增加调度的灵活性,但会降低总吞吐量,因为滴灌需要更多的进程间通信(IPC)。

在我对池的块大小算法进行深入分析的此处,我将处理一个可迭代项的工作单元定义为 taskel ,以避免与池使用的“任务”一词产生命名冲突。任务(作为工作单元)包含 chunksize 个taskels。

如果无法预测taskel需要多长时间才能完成,例如优化问题,则应将 chunksize = 1 设置为防止一个工作进程在处理重负载taskel时坐在未处理的项目堆上,从而防止其任务中的其他项被分配给空闲的工作进程。

否则,如果所有的taskel都需要相同的时间来完成,则可以将 chunksize = len(iterable)// processes 设置为使任务仅分布一次到所有工作者。请注意,如果 len(iterable)/ processes 有余数,则这将产生比进程数量更多的任务(进程+1)。这可能会严重影响您的整体计算时间。有关详细信息,请阅读先前链接的答案。


顺便说一句,这是 Pool 在没有设置时内部计算chunksize的源代码部分:

    # Python 3.6, line 378 in `multiprocessing.pool.py`
    if chunksize is None:
        chunksize, extra = divmod(len(iterable), len(self._pool) * 4)
        if extra:
            chunksize += 1
    if len(iterable) == 0:
        chunksize = 0

我一直跟到最后一段。有必要设置这个吗?在一般情况下,你真的能得到比默认性能更好的东西吗?除非你处于你详细描述的特殊情况之一,否则我不确定你能猜得更好。 - roganjosh
2
在我的经验中,调整此参数是有意义的。如果所有任务需要相同的时间,那么让工人等待新的任务只会浪费时间,因此一次性分配所有任务是有意义的。 - Darkonaut
其实,是的,那很有道理。我一直以为如果没有指定就是默认行为。谢谢。 - roganjosh
1
@roganjosh 很好的提示,我添加了相关的源代码片段。 - Darkonaut

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接