我在程序中遇到了一个问题,在启动嵌套子流程后不会引发异常。也就是说,我有一个在多处理中运行的方法。过程在该进程("第一个进程"(内部,我启动了另一个多进程。过程在第二个进程上调用start后,第一个进程继续,但不引发异常,而是在引发异常时挂起。
我不知道这是预期的行为,还是我偶然发现了Python中的一个错误。这里有一个最小的例子来证明这个问题:
import multiprocessing as mp
import time
def spin_proc():
while True:
print("spin")
time.sleep(1)
def issue():
sub_proc = mp.Process(target=spin_proc)
sub_proc.start()
print("Exception called next.") # This text is printed, as expected.
raise Exception() # This exception is never raised.
print("This text is not printed.")
first_proc = mp.Process(target=issue)
first_proc.start()
输出为:
$ python3 except.py
Exception called next.
spin
spin
spin
spin
并且它将继续打印";"旋转";直到我点击Ctrl-C。我本以为会引发异常并使程序崩溃。
我已经在Python 3.8.10和Python 3.9.2中确认了这种行为。
这是预期的行为吗?如果是,为什么?它的效果是在我的代码中隐藏异常,并意外地阻止,当试图调试新的东西却看不到任何输出时,这是非常令人沮丧的。如果它看起来是一个bug,请告诉我,我会向Python bug跟踪器报告它。
谢谢!这是按下Ctrl-C时的输出。它似乎想抛出Exception,但由于某种原因而挂起:
^CError in atexit._run_exitfuncs:
Traceback (most recent call last):
File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 27, in poll
pid, sts = os.waitpid(self.pid, flag)
KeyboardInterrupt
Process Process-1:1:
Process Process-1:
Traceback (most recent call last):
File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "except.py", line 7, in spin_proc
time.sleep(1)
KeyboardInterrupt
Traceback (most recent call last):
File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "except.py", line 13, in issue
raise Exception() # This exception is never raised.
Exception
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.8/multiprocessing/process.py", line 318, in _bootstrap
util._exit_function()
File "/usr/lib/python3.8/multiprocessing/util.py", line 357, in _exit_function
p.join()
File "/usr/lib/python3.8/multiprocessing/process.py", line 149, in join
res = self._popen.wait(timeout)
File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 47, in wait
return self.poll(os.WNOHANG if timeout == 0.0 else 0)
File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 27, in poll
pid, sts = os.waitpid(self.pid, flag)
KeyboardInterrupt
好吧,这可能是我的用户错误。我在推特上发布了这个问题,用户@stringleydimbu1指出,我可以使用守护进程标志产生预期的行为。具体来说,您可以更改这一行:
sub_proc = mp.Process(target=spin_proc)
至
sub_proc = mp.Process(target=spin_proc, daemon=True)
程序的运行与预期的一样。守护进程标志告诉python在父级死亡的情况下杀死所有子级。如果没有这些,它一定一直在无限期地等待孩子完成。令我惊讶的是,例外情况会一直存在,而不是什么都不做,但由于我没有彻底阅读文档,我无法判断这种行为是否真的出乎意料。