我有一段同时执行的异步代码:
@tornado.web.asynchronous
def execute(self, func, *args):
def callback(future):
try:
to_return = json.dumps(future.result())
self.write(to_return)
self.flush()
self.finish()
except:
error = error = self.get_exception()
self.set_status(500)
self.finish(json.dumps({"error": error))
EXECUTOR.submit(
partial(func, *args)
).add_done_callback(
lambda future: tornado.ioloop.IOLoop.instance().add_callback(
partial(callback, future)))
def get_exception(self):
exc_type, exc_obj, tb = sys.exc_info()
f = tb.tb_frame
lineno = tb.tb_lineno
filename = f.f_code.co_filename
linecache.checkcache(filename)
line = linecache.getline(filename, lineno, f.f_globals)
return {'error_msg': 'LINE {} "{}"): {}, {}'.format(filename, lineno, line.strip(), exc_obj, exc_obj)}
这很有效,除非在函数中某处抛出执行,堆栈跟踪只返回到它在回调中抛出的位置(即执行未来的位置),而不是它实际发生的位置代码。
是否有可能在最初抛出它的实际函数中捕获异常?
答案 0 :(得分:1)
在python 3中,它应该正常工作;在python 2中你运气不好,虽然我认为你可以在ThreadPoolExecutor周围编写一个能够捕获更多细节的包装器。
Python的异常/回溯模型在Python 2和3之间发生了变化:在python 3中,Exception对象带有自己的回溯信息,而在python 2中,回溯是一个单独的对象(通常通过sys.exc_info三元组访问) )。由于concurrent.futures包是从Python 3反向移植的,它只捕获异常本身,而不是exc_info三元组,因此回溯丢失。
Tornado的未来类(tornado.concurrent.Future)有一些扩展来捕获python 2中的回溯(set_exc_info()方法)。我想你可以做这样的事情(未经测试)来替换executor.submit:
def submit_with_traceback(executor, func, *args):
tornado_future = tornado.concurrent.Future()
def wrapper():
try:
result = func(*args)
except:
tornado.future.set_exc_info(sys.exc_info())
tornado_future.set_result(result)
# executor.submit() returns a concurrent.futures.Future; ignore it
executor.submit(wrapper)
return tornado_future