使用多进程时获取堆栈跟踪的最佳方法是什么?

17

我想知道在使用multiprocessing模块执行函数时,出现异常时获取堆栈跟踪的最佳方法。以下是一个示例:

import multiprocessing

def square(x):
    raise Exception("Crash.")
    return x**2

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=4)
    results = pool.map_async(square, range(5))
    for result in results.get():
        print result

这将打印:

Traceback (most recent call last):
  File "/extra/workspace/Playground/src/multiproc/multiproc_debug.py", line 11, in <module>
    for result in results.get():
  File "/extra/Python 2.6/lib/python2.6/multiprocessing/pool.py", line 422, in get
    raise self._value
Exception: Crash.

所以没有有用的堆栈跟踪,这相当令人恼火。我目前的解决方案是:

import multiprocessing
import traceback

def square(x):
    try:
        # some more code...
        raise Exception("Crash.")
    except Exception, exception:
        print exception
        traceback.print_exc()
        raise
    return x**2

有没有一种方法可以获得这种行为而不需要所有的样板代码?如果没有,为什么不包括这个功能?

编辑:可以使用装饰器来简化样板代码,但我不知道标准库是否包含这样的装饰器?

3个回答

11

看起来你应该避免从主函数中抛出异常。相反,你可以捕获它,将其视为返回给主程序的值,然后在那里重新抛出它。Python中重新抛出异常有更多细节。


不幸的是,这个问题的这一部分仍然没有解决方案:“有没有一种方法可以在没有所有样板代码的情况下获得这种行为?”(适用于Python2.7,因为3.x包括修复)。 - guettli

4

2

Python 2

我已经编写了如下的装饰器实现。 注意使用了functools.wraps,否则multiprocessing将会失败。

def full_traceback(func):
    import traceback, functools
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            msg = "{}\n\nOriginal {}".format(e, traceback.format_exc())
            raise type(e)(msg)
    return wrapper

可以在https://dev59.com/NW025IYBdhLWcg3wPzfL#43223455中找到一个例子。

Python 3

正如Paige Lo所提到的,现在在Python 3中,multiprocessing.pool.Asyncget方法返回完整的回溯信息,请参见http://bugs.python.org/issue13831


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接