Exception thrown in multiprocessing Pool not detected

后端 未结 9 827
灰色年华
灰色年华 2020-11-29 18:44

It seems that when an exception is raised from a multiprocessing.Pool process, there is no stack trace or any other indication that it has failed. Example:

         


        
9条回答
  •  生来不讨喜
    2020-11-29 19:20

    I have a reasonable solution for the problem, at least for debugging purposes. I do not currently have a solution that will raise the exception back in the main processes. My first thought was to use a decorator, but you can only pickle functions defined at the top level of a module, so that's right out.

    Instead, a simple wrapping class and a Pool subclass that uses this for apply_async (and hence apply). I'll leave map_async as an exercise for the reader.

    import traceback
    from multiprocessing.pool import Pool
    import multiprocessing
    
    # Shortcut to multiprocessing's logger
    def error(msg, *args):
        return multiprocessing.get_logger().error(msg, *args)
    
    class LogExceptions(object):
        def __init__(self, callable):
            self.__callable = callable
    
        def __call__(self, *args, **kwargs):
            try:
                result = self.__callable(*args, **kwargs)
    
            except Exception as e:
                # Here we add some debugging help. If multiprocessing's
                # debugging is on, it will arrange to log the traceback
                error(traceback.format_exc())
                # Re-raise the original exception so the Pool worker can
                # clean up
                raise
    
            # It was fine, give a normal answer
            return result
    
    class LoggingPool(Pool):
        def apply_async(self, func, args=(), kwds={}, callback=None):
            return Pool.apply_async(self, LogExceptions(func), args, kwds, callback)
    
    def go():
        print(1)
        raise Exception()
        print(2)
    
    multiprocessing.log_to_stderr()
    p = LoggingPool(processes=1)
    
    p.apply_async(go)
    p.close()
    p.join()
    

    This gives me:

    1
    [ERROR/PoolWorker-1] Traceback (most recent call last):
      File "mpdebug.py", line 24, in __call__
        result = self.__callable(*args, **kwargs)
      File "mpdebug.py", line 44, in go
        raise Exception()
    Exception
    

提交回复
热议问题