Python 在嵌套 multiprocessing.Process 上调用 start 后未引发异常
Python not raising exception after calling start on a nested multiprocessing.Process
我 运行 遇到程序中的一个问题,在启动嵌套子进程后没有抛出异常。也就是说,我有一个方法,我 运行 在 multiprocessing.Process 中。在该进程(“第一个进程”)内,我启动了另一个 multiprocessing.Process。在第二个进程上调用 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
它会无限期地继续打印“spin”,直到我按下 Ctrl-C。我本以为会引发异常并使程序崩溃。
我已在 Python 3.8.10 和 Python 3.9.2 中确认此行为。
这是预期的行为吗?如果是这样,为什么?它具有在我的代码中隐藏异常并意外阻塞的效果,这在尝试调试新内容但看不到任何输出时非常令人沮丧。如果它看起来是一个错误,请告诉我,我会将其报告给 Python 错误跟踪器。
谢谢!这是按 Ctrl-C 时的输出。它似乎想抛出异常,但由于某种原因挂起:
^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
好吧,看来这可能是我的用户错误。我将这个问题发布到推特上,其中用户@strinkleydimbu1 指出我可以使用守护程序标志产生预期的行为。具体你可以改变这一行:
sub_proc = mp.Process(target=spin_proc)
至
sub_proc = mp.Process(target=spin_proc, daemon=True)
并且程序运行符合预期。如果 parent 死亡,守护进程标志告诉 python 杀死所有 children。如果没有这个,它一定会无限期地等待 child 完成。令我惊讶的是,异常只会挂起而不是做任何事情,但由于我没有彻底阅读文档,我不能说这种行为是否真的出乎意料。
我 运行 遇到程序中的一个问题,在启动嵌套子进程后没有抛出异常。也就是说,我有一个方法,我 运行 在 multiprocessing.Process 中。在该进程(“第一个进程”)内,我启动了另一个 multiprocessing.Process。在第二个进程上调用 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
它会无限期地继续打印“spin”,直到我按下 Ctrl-C。我本以为会引发异常并使程序崩溃。
我已在 Python 3.8.10 和 Python 3.9.2 中确认此行为。
这是预期的行为吗?如果是这样,为什么?它具有在我的代码中隐藏异常并意外阻塞的效果,这在尝试调试新内容但看不到任何输出时非常令人沮丧。如果它看起来是一个错误,请告诉我,我会将其报告给 Python 错误跟踪器。
谢谢!这是按 Ctrl-C 时的输出。它似乎想抛出异常,但由于某种原因挂起:
^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
好吧,看来这可能是我的用户错误。我将这个问题发布到推特上,其中用户@strinkleydimbu1 指出我可以使用守护程序标志产生预期的行为。具体你可以改变这一行:
sub_proc = mp.Process(target=spin_proc)
至
sub_proc = mp.Process(target=spin_proc, daemon=True)
并且程序运行符合预期。如果 parent 死亡,守护进程标志告诉 python 杀死所有 children。如果没有这个,它一定会无限期地等待 child 完成。令我惊讶的是,异常只会挂起而不是做任何事情,但由于我没有彻底阅读文档,我不能说这种行为是否真的出乎意料。