如何捕获使用 multiprocessing.Process() 执行的函数抛出的异常 (python)

Mic*_*eld 8 python exception multiprocessing python-3.x

如何捕获使用 执行的进程中的异常multiprocessing.Process()

考虑以下 python 脚本,该脚本failFunction()使用以下命令在子进程内部执行一个简单的(立即引发运行时错误):mulitprocessing.Process()

#!/usr/bin/env python3
import multiprocessing, time

# this function will be executed in a child process asynchronously
def failFunction():
   raise RuntimeError('trust fall, catch me!')

# execute the helloWorld() function in a child process in the background
process = multiprocessing.Process(
 target = failFunction,
)
process.start()

# <this is where async stuff would happen>
time.sleep(1)

# try (and fail) to catch the exception
try:
    process.join()
except Exception as e:
    print( "This won't catch the exception" )
Run Code Online (Sandbox Code Playgroud)

从下面的执行中可以看出,尝试包装实际上.join()没有捕获异常

user@host:~$ python3 example.py 
Process Process-1:
Traceback (most recent call last):
  File "/usr/lib/python3.7/multiprocessing/process.py", line 297, in _bootstrap
    self.run()
  File "/usr/lib/python3.7/multiprocessing/process.py", line 99, in run
    self._target(*self._args, **self._kwargs)
  File "example4.py", line 6, in failFunction
    raise RuntimeError('trust fall, catch me!')
RuntimeError: trust fall, catch me!
user@host:~$ 
Run Code Online (Sandbox Code Playgroud)

如何更新上面的脚本以实际捕获使用在子进程内部执行的函数的异常multiprocessing.Process()

Mic*_*eld 5

这可以通过使用语句重载类run()中的方法并设置一个来获取子进程中引发的任何异常并将其存储到named的实例字段中来实现:multiprocessing.Proccess()try..exceptPipe()exception

#!/usr/bin/env python3
import multiprocessing, traceback, time

class Process(multiprocessing.Process):

    def __init__(self, *args, **kwargs):
        multiprocessing.Process.__init__(self, *args, **kwargs)
        self._pconn, self._cconn = multiprocessing.Pipe()
        self._exception = None

    def run(self):
        try:
            multiprocessing.Process.run(self)
            self._cconn.send(None)
        except Exception as e:
            tb = traceback.format_exc()
            self._cconn.send((e, tb))
            #raise e  # You can still rise this exception if you need to

    @property
    def exception(self):
        if self._pconn.poll():
            self._exception = self._pconn.recv()
        return self._exception


# this function will be executed in a child process asynchronously
def failFunction():
   raise RuntimeError('trust fall, catch me!')

# execute the helloWorld() function in a child process in the background
process = Process(
 target = failFunction,
)
process.start()

# <this is where async stuff would happen>
time.sleep(1)

# catch the child process' exception
try:
    process.join()
    if process.exception:
        raise process.exception
except Exception as e:
    print( "Exception caught!" )
Run Code Online (Sandbox Code Playgroud)

执行示例:

user@host:~$ python3 example.py 
Exception caught!
user@host:~$ 
Run Code Online (Sandbox Code Playgroud)

解决方案取自这个答案: