Python 2.7.3 多进程池挂起

5 投票
1 回答
1523 浏览
提问于 2025-04-27 22:06

我在ipython中有一段代码,子进程尝试执行 sys.exit(...),结果导致父进程卡住了。这算不算一个bug呢?有没有什么解决办法?

In [1]: from multiprocessing import Pool

In [2]: def f():
   ...:     import sys
   ...:     sys.exit('exiting system...')
   ...:    

In [3]: p = Pool(processes=2)

In [4]: r = p.apply_async(f, [])

In [5]: r.get()   <---- it is hanging here forever.

我也试过用 raise SystemExit(...) 来代替 sys.exit(...),但是结果还是一样。唯一我知道的解决办法是用 raise Exception(...),这个方法效果很好。

我明白 sys.exitraise SystemExit 基本上是一样的,但这个异常应该被传递给父进程,所以 r.get() 应该能接收到这个异常,对吧?可是它似乎在 recv 调用时卡住了。这是 multiprocessing 模块的bug吗?

暂无标签

1 个回答

2

你在调用 sys.exit() 时,让 Pool 的工作进程直接退出了。SystemExit 这个异常是特别处理的;当你抛出它时,抛出它的进程就会退出。这个异常不会传递给调用它的地方。所以在你的例子中,工作进程根本没有把任何东西返回给父进程。结果,父进程就会一直等待子进程返回一些永远不会返回的东西。想了解更多这种行为,可以看看 这个问题

我认为这是一个bug,当子进程退出时,pool 应该被标记为坏掉了,所有未完成的任务应该被终止。这就是 concurrent.futures.ProcessPoolExecutor 的行为。我实际上已经 提交了一个补丁,希望把这种行为添加到 multiprocessing.Pool 中,但到现在为止还没有被审核。

回到你最初的问题。看起来你想让 父进程 也退出,而不仅仅是子进程。要做到这一点,你需要把某个对象返回给父进程,然后在父进程收到这个对象时让它退出。看起来你发现可以通过简单地抛出一个 Exception 来实现这一点。

撰写回答