【问题标题】:Why does the output show that pool is closed multiple times when it is actually processing?为什么输出显示池在实际处理时多次关闭?
【发布时间】:2020-08-20 15:54:03
【问题描述】:

为什么输出显示池在实际处理时已关闭?

res.get() 是阻止多处理的阻塞操作吗?

为什么会打印Now the pool is closed and no longer available 5 次?

from multiprocessing import Pool, TimeoutError
import time
import os

def f(x):
    time.sleep(5)
    return x*x

if __name__ == '__main__':
    # start 4 worker processes
    with Pool(processes=4) as pool: 
        for i in range(5):
            # evaluate "f(20)" asynchronously
            res = pool.apply_async(f, (20,))      # runs in *only* one process
            print(res.get())

    
# exiting the 'with'-block has stopped the pool
print("Now the pool is closed and no longer available")

输出:

Now the pool is closed and no longer available
Now the pool is closed and no longer available
Now the pool is closed and no longer available
Now the pool is closed and no longer available
400
400
400
400
400
Now the pool is closed and no longer available

【问题讨论】:

    标签: python python-3.x python-multiprocessing


    【解决方案1】:

    在python的multiprocessing模块中,当一个新进程被创建时,它会导入__main__模块*。基本上它运行传递给主线程的同一个文件,但是任何if __name__ == '__main__': 块都会失败,因为__name__ 将是别的东西。然后它通过pickle 传递要调用的函数和调用它的参数。

    基本上当您调用with Pool(processes=4) as pool: 时,4 个子进程各自启动并执行打印语句。

    您的第二个问题“res.get() 是否为阻塞操作”的答案是肯定的。在等待结果之前,您应该将所有工作提交到处理池以使其启动。

    移动您的打印语句并将工作提交与结果检索分开可能看起来像这样:

    from multiprocessing import Pool, TimeoutError
    import time
    import os
    
    def f(x):
        time.sleep(5)
        return x*x
    
    if __name__ == '__main__':
        # start 4 worker processes
        with Pool(processes=4) as pool:
            future_results = []
            for i in range(5):
                # evaluate "f(20)" asynchronously
                future_results.append(pool.apply_async(f, (20,)))
            #get results after submitting all work
            for res in future_results:
                print(res.get())
    
        #move this inside "if __name__ == '__main__':" so it isn't executed in child processes.
        # exiting the 'with'-block has stopped the pool
        print("Now the pool is closed and no longer available")
    

    *在 Unix 上它做的事情有点不同。这就是文档中提到的 Spawn 和 Fork 之间的区别。

    【讨论】:

    • res.get() 必须在with 块内吗?如果放在with 块之外有什么不同吗?
    • @variable kind of ... AsyncResult 由池处理的主进程的线程提供其结果。当到达with 块的末尾时(如果您不等待结果,则立即终止),池终止(即使它仍在工作)并且该线程停止,因此永远不会设置结果。使用超时调用get 将简单地等待超时,然后引发TimeoutError。在退出 with 块之前,您需要某种方式“等待”所有结果都得到处理。
    • 此行为的一个有趣用例可能是希望在固定时间内完成尽可能多的工作。你可以提交一堆工作,然后time.sleep() 一段固定的时间,然后在with 块之外检查它完成了多少。
    猜你喜欢
    • 1970-01-01
    • 2017-11-19
    • 1970-01-01
    • 1970-01-01
    • 2019-11-15
    • 2020-09-15
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    相关资源
    最近更新 更多