13

我写了一个程序,它有一个定期从主程序调用的协程,ioloop如下所示:

from tornado import ioloop, web, gen, log
tornado.log.enable_pretty_printing()
import logging; logging.basicConfig()

@gen.coroutine
def callback():
    print 'get ready for an error...'
    raise Exception()
    result = yield gen.Task(my_async_func)

l = ioloop.IOLoop.instance()
cb = ioloop.PeriodicCallback(callback, 1000, io_loop=l)
cb.start
l.start()

我得到的输出很简单:

$ python2 app.py
get ready for an error...
get ready for an error...
get ready for an error...
get ready for an error...

raise Exception()默默无视!如果我将回调更改为

def callback():
    print 'get ready for an error...'
    raise Exception()

我得到了我期望(和需要)的完整堆栈跟踪。使用协程时如何获取堆栈跟踪?

4

2 回答 2

7

@tornado.gen.coroutine使函数返回tornado.concurrent.Future对象,因此您不必将其包装,tornado.gen.Task但您可以使用yield关键字调用它:

@tornado.gen.coroutine
def inner():
    logging.info('inner')

@tornado.gen.coroutine
def outer():
    logging.info('outer')
    yield inner()

以这种方式装饰的函数中的异常被包装到此tornado.concurrent.Future对象中,稍后可以使用其exception()方法返回。在您的情况下tornado.ioloop.PeriodicCallback调用您的回调方法,然后它只是丢弃返回的tornado.concurrent.Future对象及其包含的异常。要检测异常,您可以使用链式调用:

@tornado.gen.coroutine
def inner():
    raise Exception()

@tornado.gen.coroutine
def outer():
    try:
        yield inner()   
    except Exception, e:
        logging.exception(e)

但在你的情况下,在投掷后抓住它实际上更容易:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import tornado.gen
import tornado.ioloop
import tornado.options
import logging

tornado.options.parse_command_line()

@tornado.gen.coroutine
def callback():
    logging.info('get ready for an error...')
    try:
        raise Exception()   
    except Exception, e:
        logging.exception(e)

main_loop = tornado.ioloop.IOLoop.instance()
scheduler = tornado.ioloop.PeriodicCallback(callback, 1000, io_loop = main_loop)
scheduler.start()
main_loop.start()

@gen.engine不会使函数返回 atornado.concurrent.Future所以异常不会被包装。

于 2013-05-29T15:13:46.843 回答
4

我不明白为什么,但更改@gen.coroutine@gen.engine允许异常正确冒泡。它仍然可以异步工作。

于 2013-05-25T01:09:35.130 回答