捕获父进程中子进程引发的异常

时间:2015-11-19 00:48:16

标签: python python-multiprocessing

我正在尝试捕获子进程引发的异常,并且遇到了一些问题。我的代码的要点是:

class CustomException(Exception):
  def __init__(self, msg):
    self.msg = msg

  def __str__(self):
    return self.msg    

def update(partition):
  if os.getpid() % 2 == 0:
    raise CustomException('PID was divisible by 2!')
  else:
    # Do something fancy

if __name__ == '__main__':
  try:
    some_response = get_response_from_another_method()
    partition_size = 100
    p = Pool(config.NUMBER_OF_PROCESSES)
    for i in range(0, NUMBER_OF_PROCESSES):
      partition = get_partition(some_response, partition_size)
      x = p.apply_async(update, args=(partition,))
    x.get()
    p.close()
    p.join()
  except CustomException as e:
    log.error('There was an error')
    if email_notifier.send_notification(e.msg):
      log.debug('Email notification sent')
    else:
      log.error('An error occurred while sending an email.')

当我跑步时,我看到了:

  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py", line 532, in __bootstrap_inner
    self.run()
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py", line 484, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/multiprocessing/pool.py", line 259, in _handle_results
    task = get()
TypeError: ('__init__() takes exactly 2 arguments (1 given)', <class 'CustomException'>, ())

是否有一些设施可以做到这一点?谢谢!

1 个答案:

答案 0 :(得分:1)

简而言之,这在Python 2中是一个怪癖,在bug report中引用了一个相关的问题。它与如何腌制异常有关。最简单的解决方案可能是改变CustomException,以便调用其父类初始值设定项。或者,如果你能够,我建议你转向Python 3。

例如,此代码在Python 2和Python 3中均可正常工作:

from multiprocessing import Pool

class CustomException(Exception):
    pass

def foo():
    raise CustomException('PID was divisible by 2!')

pool = Pool()
result = pool.apply_async(foo, [])

但是如果我们改变CustomException以便它有一个必需的参数:

class CustomException(Exception):
    def __init__(self, required):
        self.required = required

上面的示例导致在Python 2下引发TypeError。它在Python 3下工作。

问题是CustomException继承了Exception的{​​{1}}方法,该方法告诉Python如何挑选实例。继承的__reduce____reduce__的呼叫签名一无所知,因此无法正确进行解链。

快速解决方法是简单地调用父类的CustomException

__init__

但是因为你真的没有对这个消息做任何特别的事情,为什么不定义:

class CustomException(Exception):
    def __init__(self, msg):
        super(Exception, self).__init__()
        self.msg = msg