我试图从multiprocessing.Process获取一个追溯对象。不幸的是,通过管道传递异常信息不起作用,因为无法腌制回溯对象:
def foo(pipe_to_parent): try: raise Exception('xxx') except: pipe_to_parent.send(sys.exc_info()) to_child, to_self = multiprocessing.Pipe() process = multiprocessing.Process(target = foo, args = (to_self,)) process.start() exc_info = to_child.recv() process.join() print traceback.format_exception(*exc_info) to_child.close() to_self.close()
追溯:
Traceback (most recent call last): File "/usr/lib/python2.6/multiprocessing/process.py", line 231, in _bootstrap self.run() File "/usr/lib/python2.6/multiprocessing/process.py", line 88, in run self._target(*self._args, **self._kwargs) File "foo", line 7, in foo to_parent.send(sys.exc_info()) PicklingError: Can't pickle <type 'traceback'>: attribute lookup __builtin__.traceback failed
还有另一种访问异常信息的方法吗?我想避免传递格式化的字符串。
使用tblib您可以传递包装的异常并在以后重新引发它们:
tblib
import tblib.pickling_support tblib.pickling_support.install() from multiprocessing import Pool import sys class ExceptionWrapper(object): def __init__(self, ee): self.ee = ee __, __, self.tb = sys.exc_info() def re_raise(self): raise self.ee.with_traceback(self.tb) # for Python 2 replace the previous line by: # raise self.ee, None, self.tb # example of how to use ExceptionWrapper def inverse(i): """ will fail for i == 0 """ try: return 1.0 / i except Exception as e: return ExceptionWrapper(e) def main(): p = Pool(1) results = p.map(inverse, [0, 1, 2, 3]) for result in results: if isinstance(result, ExceptionWrapper): result.re_raise() if __name__ == "__main__": main()
因此,如果您在远程进程中捕获到异常,则将其包装ExceptionWrapper,然后将其传递回去。调用re_raise()主流程即可完成工作。
ExceptionWrapper
re_raise()