在多处理池

时间:2017-08-01 15:43:34

标签: python multiprocessing shutdown pool worker

我有一个简单的服务器:

from multiprocessing import Pool, TimeoutError
import time
import os


if __name__ == '__main__':
    # start worker processes
    pool = Pool(processes=1)

    while True:
        # evaluate "os.getpid()" asynchronously
        res = pool.apply_async(os.getpid, ())  # runs in *only* one process
        try:
            print(res.get(timeout=1))             # prints the PID of that process
        except TimeoutError:
            print('worker timed out')

        time.sleep(5)

    pool.close()
    print("Now the pool is closed and no longer available")
    pool.join()
    print("Done")

如果我运行这个,我会得到类似的东西:

47292
47292

然后在服务器运行时我kill 47292。启动了新的工作进程,但服务器的输出为:

47292
47292
worker timed out
worker timed out
worker timed out

池仍在尝试向旧工作进程发送请求。

我已经完成了在服务器和工作程序中捕获信号的一些工作,我可以获得稍微好一点的行为,但服务器似乎仍在等待关闭时死亡的孩子(即。pool.join()永远不会结束)工人被杀了。

处理工人死亡的正确方法是什么?

如果没有工人死亡,那么从服务器进程中正常关闭工作人员似乎才有效。

(在Python 3.4.4上,但如果有帮助的话,很乐意升级。)

更新: 有趣的是,如果使用processes = 2创建池并且您杀死一个工作进程,等待几秒钟并终止另一个进程,则不会发生此工作者超时问题。但是,如果你快速连续杀死两个工作进程,那么“工人超时”问题就会再次出现。

或许相关的是,当问题发生时,终止服务器进程将使工作进程继续运行。

1 个答案:

答案 0 :(得分:3)

此行为来自multiprocessing.Pool的设计。当你杀死一个工人时,你可能会杀死持有call_queue.rlock的人。当这个过程在持有锁定时被杀死时,其他任何进程都无法再读取call_queue,打破Pool,因为它无法与其工作人员进行通信。
所以实际上没有办法杀死一个工人,并确保你的Pool之后仍然可以,因为你可能会陷入僵局。

multiprocessing.Pool无法处理工人死亡。您可以尝试使用concurrent.futures.ProcessPoolExecutor代替(使用略有不同的API)来处理默认情况下进程失败的情况。当进程在ProcessPoolExecutor中死亡时,整个执行程序都会关闭,并且您会收到BrokenProcessPool错误。

请注意,此实现中还有其他死锁,应在loky中修复。 (免责声明:我是这个库的维护者)。此外,loky还允许您使用executor和方法ReusablePoolExecutor调整现有_resize的大小。如果您有兴趣,请告诉我,从这个软件包开始,我可以为您提供一些帮助。 (我意识到我们仍然需要对文档进行一些工作...... 0_0)