我有一个简单的服务器:
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 创建线程池,并且您杀死一个工作进程,等待几秒钟再杀死另一个工作进程,则此工作超时问题不会发生。但是,如果您快速连续杀死两个工作进程,则“工作超时”问题将再次出现。
也许相关的是当问题发生时,杀死服务器进程将使工作进程继续运行。
Pool
是由死锁导致的,正如答案所述。如果你想处理一个工作进程的死亡,你需要明确死因:谋杀还是意外? :) 根据这些精确的情况,你可以使用不同的设计。关于工作进程的非python死亡的主要问题在于无法保证同步原语(Lock
)不会陷入不可恢复的状态。 - Thomas Moreau