【发布时间】:2015-07-02 22:58:16
【问题描述】:
假设我有两个这样工作的函数:
@tornado.gen.coroutine
def f():
for i in range(4):
print("f", i)
yield tornado.gen.sleep(0.5)
@tornado.gen.coroutine
def g():
yield tornado.gen.sleep(1)
print("Let's raise RuntimeError")
raise RuntimeError
一般来说,函数f 可能包含无限循环并且永远不会返回(例如它可以处理一些队列)。
我想做的是能够随时中断它。
最明显的方法行不通。异常仅在函数 f 退出后引发(如果它是无穷无尽的,它显然永远不会发生)。
@tornado.gen.coroutine
def main():
try:
yield [f(), g()]
except Exception as e:
print("Caught", repr(e))
while True:
yield tornado.gen.sleep(10)
if __name__ == "__main__":
tornado.ioloop.IOLoop.instance().run_sync(main)
输出:
f 0
f 1
Let's raise RuntimeError
f 2
f 3
Traceback (most recent call last):
File "/tmp/test/lib/python3.4/site-packages/tornado/gen.py", line 812, in run
yielded = self.gen.send(value)
StopIteration
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
<...>
File "test.py", line 16, in g
raise RuntimeError
RuntimeError
也就是说,只有当两个协程都返回(两个期货都解析)时才会引发异常。
tornado.gen.WaitIterator 部分解决了这个问题,但它有问题 (unless I'm mistaken)。但这不是重点。
它仍然没有解决中断现有协程的问题。即使启动协程的函数退出,协程也会继续运行。
编辑:似乎 Tornado 并不真正支持协程取消,这与 Python 的 asyncio 不同,您可以轻松地在每个屈服点抛出 CancelledError。
【问题讨论】:
-
普通的
generator.throw函数不能与 Tornado 协程一起工作吗?而且,如果没有,是否没有记录在案的替代品呢? (对于基于yield from的协程,如在stdlib 的asyncio中,有一些棘手的问题,但对于基于yield的蹦床协程不应该是一个问题。) -
tornado.gen.coroutine装饰器使函数返回未来而不是生成器,并且底层生成器似乎没有暴露。 Tornado 期货也不支持cancel()方法(它的实现总是返回False)。 -
哦,好吧,我想我对 Tornado 的了解还不够,无法在这里提供帮助。希望别人这样做。 :)
标签: python exception tornado yield coroutine