为什么Pool慢于相同数量的进程

时间:2017-11-20 02:56:31

标签: python multiprocessing python-multiprocessing

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

共享依赖:

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

from community import best_partition

以下是使用Process的更快实施。 [UPDATE]重构以控制与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()

1 个答案:

答案 0 :(得分:1)

通常当一个池和一堆进程之间存在差异时(可能是为了它们的利益),正是您的数据集和执行的任务定义了结果。

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

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

正如我所说,这是纯粹的推测,但在你的例子中,你实际上作为参数传递给你的工人有很大的不同,这可能就是解释。