I am trying to get hold of a traceback object from a multiprocessing.Process. Unfortunately passing the exception info through a pipe does not work because traceback objects can not be pickled:
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:
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
Is there another way to access the exception info? I'd like to avoid passing the formatted string.
Items can be retrieved from the queue by calls to get(). By default, the call to get() will block until an item is available to retrieve from the queue and will not use a timeout. You can learn more about multiprocessing queues in the tutorial: Multiprocessing Queue in Python.
Method 1: By using print_exc() method. This method prints exception information and stack trace entries from traceback object tb to file.
If a task issued asynchronously raises an exception, it will be caught by the process pool and re-raised if you call get() function in the AsyncResult object in order to get the result. It means that you have two options for handling exceptions in tasks, they are: Handle exceptions within the task function.
Using tblib
you can pass wrapped exceptions and reraise them later:
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()
So, if you catch an exception in your remote process, wrap it with ExceptionWrapper
and then pass it back. Calling re_raise()
in the main process will do the work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With