为什么 Pool 比相同数量的 Processes 慢

Why is Pool slower than the same number of Processes

我最近尝试将一些并行进程重构到一个池中,令我惊讶的是该池花费的时间几乎是纯进程的两倍。请假设它们 运行 在具有相同内核数的同一台机器上。我希望有人可以解释为什么我使用 Pool 的实现需要更长的时间,并可能提供一些建议:

共享依赖项:

https://github.com/taynaud/python-louvain

from community import best_partition

这是使用 Process 的更快实现。 [更新] 重构以控制与 Pool 实现相同的活动进程数,速度更快:

processes = []
pipes = []

def _get_partition(send_end):
    send_end.send(best_partition(a_graph, resolution=res, randomize=rand))

for idx in range(iterations):
    recv_end, send_end = Pipe(False)
    p = Process(target=_get_partition, args=(send_end,))
    processes.append(p)
    pipes.append(recv_end)

running_procs = []
finished_procs = []
while len(finished_procs) < iterations:
    while len(running_procs) < n_cores and len(processes):
        proc = processes.pop()
        proc.start()
        running_procs.append(proc)

    for idx, proc in enumerate(running_procs):
        if not proc.is_alive():
            finished_procs.append(running_procs.pop(idx))

for p in finished_procs:
    p.join()

partitions = [pipe.recv() for pipe in pipes]

这里是较慢的 Pool 实现。无论给定池有多少个进程,这仍然较慢:

pool = Pool(processes=n_cores)
results = [
    pool.apply_async(
        best_partition,
        (a_graph,),
        dict(resolution=res, randomize=rand)
    ) for i in range(iterations)
]
partitions = [res.get() for res in results]
pool.close()
pool.join()

通常,当一个池和一组进程之间存在差异时(这可能对任何一个都有好处),定义结果的是您的数据集和执行的任务。

在不知道你的 a_graph 是什么的情况下,我胡乱猜测它是个大东西。在您的流程模型中,您依赖子流程中的内存中副本。在您的 Pool 模型中,每次调用时,您都会将 a_graph 的副本作为参数传输给每个工作人员。这实际上是作为队列实现的。在您的流程模型中,当 Python 解释器调用 fork() 时,您的子流程会在 C 级别获取此副本。这比通过队列传输大型 Python 对象、字典、数组或其他任何东西要快得多。

如果任务只需要很短的时间就可以完成,则情况正好相反。在这种情况下,Pool 是性能更好的解决方案,因为 Pool 将任务传递给已经 运行ning 个进程。不需要在每个任务之后重新创建流程。在这种情况下,创建大量新进程所需的开销 运行 只需几分之一秒,这会减慢进程的实施速度。

正如我所说,这纯粹是推测,但在您的示例中,您实际作为参数传输给您的工作人员的内容存在显着差异,这可能就是解释。