如何重用多处理池?

时间:2018-12-24 10:10:43

标签: python-3.x multiprocessing

底部是我现在拥有的代码。似乎工作正常。但是,我并不完全理解。我以为如果没有.join(),在该池完成执行之前,我会冒着进入下一个for循环的风险。我们不需要这3条注释掉的行吗?

另一方面,如果我采用.close().join()的方式,是否有任何方法可以“重新打开”已关闭的池而不是每次都Pool(6)

import multiprocessing as mp
import random as rdm
from statistics import stdev, mean
import time


def mesh_subset(population, n_chosen=5):
    chosen = rdm.choices(population, k=n_chosen)
    return mean(chosen)


if __name__ == '__main__':
    population = [x for x in range(20)]
    N_iteration = 10
    start_time = time.time()
    pool = mp.Pool(6)
    for i in range(N_iteration):
        print([round(x,2) for x in population])
        print(stdev(population))
        # pool = mp.Pool(6)
        population = pool.map(mesh_subset, [population]*len(population))
        # pool.close()
        # pool.join()
    print('run time:', time.time() - start_time)

1 个答案:

答案 0 :(得分:1)

建立一个工人池是相对昂贵的事情,因此(如果可能)应该只执行一次(通常在脚本开始时)。

pool.map命令将阻塞,直到所有任务完成。毕竟,它返回结果列表。除非在所有输入上都调用mesh_subset并为每个输入返回结果,否则无法这样做。相反,pool.apply_async之类的方法不会阻塞。 apply_async返回带有get方法的ApplyResult对象,该方法将阻塞,直到从工作进程获取结果为止。

pool.close sets the worker handler's state关闭。这会导致处理程序终止signal the workers

pool.join阻塞,直到所有工作进程都终止。

因此,您不需要调用-实际上,您不应该调用pool.closepool.join,直到您完成池为止。一旦工人被派遣信号终止(通过pool.close),就无法“重新打开”他们。您将需要启动一个新池。


在您的情况下,由于您要做希望循环等待直到所有任务完成,因此使用pool.apply_async而不是pool.map没有好处。但是,如果您使用pool.apply_async,则可以通过调用get而不是诉诸于关闭并重新启动池来获得与以前相同的结果:

# you could do this, but using pool.map is simpler
for i in range(N_iteration):
    apply_results = [pool.apply_async(mesh_subset, [population]) for i in range(len(population))]
    # the call to result.get() blocks until its worker process (running
    # mesh_subset) returns a value
    population = [result.get() for result in apply_results]

循环完成后,len(population)不变。


如果您不希望在所有任务完成之前阻塞每个循环,则可以使用apply_async的{​​{1}}功能:

callback

现在,当任何N_pop = len(population) result = [] for i in range(N_iteration): for i in range(N_pop): pool.apply_async(mesh_subset, [population]), callback=result.append) pool.close() pool.join() print(result) 返回mesh_subset时, return_value被调用。对result.append(return_value)的呼叫不会 块,因此apply_async任务被推入N_iteration * N_pop s任务 一次全部排队。但是,由于池中有6个工人,最多只能有6个电话 pool在任何给定时间运行。当工人完成任务时, 谁完成了第一个呼叫mesh_subset的工作人员。所以 result.append(return_value)中的值是无序的。这与result不同 返回一个列表,其返回值与其对应值的顺序相同 参数列表。

除非有例外,否则pool.map最终将包含result返回值一次 所有任务都完成了。上方,N_iteration * N_poppool.close()用于 等待所有任务完成。