我处于同样的情况,我真的需要对引发的异常进行回溯。
我能够开发这个解决方法,其中包括使用以下子类ThreadPoolExecutor
.
import sys
import traceback
from concurrent.futures import ThreadPoolExecutor
class ThreadPoolExecutorStackTraced(ThreadPoolExecutor):
def submit(self, fn, *args, **kwargs):
"""Submits the wrapped function instead of `fn`"""
return super(ThreadPoolExecutorStackTraced, self).submit(
self._function_wrapper, fn, *args, **kwargs)
def _function_wrapper(self, fn, *args, **kwargs):
"""Wraps `fn` in order to preserve the traceback of any kind of
raised exception
"""
try:
return fn(*args, **kwargs)
except Exception:
raise sys.exc_info()[0](traceback.format_exc()) # Creates an
# exception of the
# same type with the
# traceback as
# message
如果您使用此子类并运行以下代码片段:
def f(x):
return x * x
data = [1, 2, 3, None, 5]
with ThreadPoolExecutorStackTraced(max_workers=len(data)) as executor:
futures = [executor.submit(f, n) for n in data]
for future in futures:
try:
print future.result()
except TypeError as e:
print e
输出将类似于:
1
4
9
Traceback (most recent call last):
File "future_traceback.py", line 17, in _function_wrapper
return fn(*args, **kwargs)
File "future_traceback.py", line 24, in f
return x * x
TypeError: unsupported operand type(s) for *: 'NoneType' and 'NoneType'
25
问题在于使用sys.exc_info()
by the futures
图书馆。来自
文档:
该函数返回一个由三个值组成的元组,这些值提供有关异常的信息
目前正在处理中。 [...]
如果堆栈上的任何位置都没有处理异常,则包含三个 None 值的元组是
回。否则,返回的值为(类型、值、回溯)。它们的含义是:类型获取
正在处理的异常的异常类型(类对象);值获取异常
参数(其关联值或 raise 的第二个参数,始终是类实例
如果异常类型是类对象); Traceback 获取一个封装了以下内容的 Traceback 对象
异常最初发生处的调用堆栈。
现在,如果你看一下源代码futures
你可以自己看看为什么回溯是
丢失:当发生异常并且要设置为Future
仅对象sys.exc_info()[1]
已通过。看:
https://code.google.com/p/pythonfutures/source/browse/concurrent/futures/thread.py https://code.google.com/p/pythonfutures/source/browse/concurrent/futures/thread.py (L:63)
https://code.google.com/p/pythonfutures/source/browse/concurrent/futures/_base.py https://code.google.com/p/pythonfutures/source/browse/concurrent/futures/_base.py (L:356)
因此,为了避免丢失回溯,您必须将其保存在某个地方。我的解决方法是换行
提交到包装器的函数,包装器的唯一任务是捕获每种异常,并且
引发相同类型的异常,其消息是回溯。通过这样做,当
引发异常,它被包装器捕获并重新引发,然后当sys.exc_info()[1]
被分配给例外Future
对象,回溯不会丢失。