tornado.gen 实现了基于生成器的协程。
注意:
本模块中的“装饰器和生成器”方法是 Python 3.5 中引入的原生协程(使用 async def 和 await)的先驱。 不需要与旧版本 Python 兼容的应用程序应该使用本机协程。 该模块的某些部分仍然适用于原生协程,特别是 multi、sleep、WaitIterator和 with_timeout。 其中一些函数在 asyncio模块中有对应的函数,它们也可以使用,尽管这两个函数不一定是 100% 兼容的。
与链接回调相比,协程提供了一种在异步环境中工作的更简单的方法。 使用协程的代码在技术上是异步的,但它被编写为单个生成器,而不是单独函数的集合。
例如,这是一个基于协程的处理程序:
class GenAsyncHandler(RequestHandler):
@gen.coroutine
def get(self):
http_client = AsyncHTTPClient()
response = yield http_client.fetch("http://example.com")
do_something_with_response(response)
self.render("template.html")
Tornado 中的异步函数返回一个 Awaitable或 Future; 产生这个对象会返回它的结果。
您还可以产出其他可缩性对象的列表或字典,它们将同时启动并并行运行; 全部完成后将返回结果列表或字典:
@gen.coroutine
def get(self):
http_client = AsyncHTTPClient()
response1, response2 = yield [http_client.fetch(url1),
http_client.fetch(url2)]
response_dict = yield dict(response3=http_client.fetch(url3),
response4=http_client.fetch(url4))
response3 = response_dict['response3']
response4 = response_dict['response4']
如果导入了 tornado.platform.twisted,也可以生成 Twisted的 Deferred对象。
在 3.2 版更改:添加了字典支持。
在 4.1 版更改: 添加了对通过 singledispatch生成 asyncio Futures 和 Twisted Deferreds 的支持。
异步生成器的装饰器。
为了与旧版本的 Python 兼容,协程也可以通过引发特殊异常 Return(value) 来“return”。
带有这个装饰器的函数返回一个 Future。
当协程内部发生异常时,异常信息将存储在 Future对象中。 您必须检查 Future对象的结果,否则您的代码可能不会注意到异常。 这意味着如果从另一个协程调用时产生函数,使用 IOLoop.run_sync 之类的东西进行顶级调用,或者将 Future传递给 IOLoop.add_future。
在 6.0 版更改: callback参数已删除。 请改用返回的可等待对象。
从协程返回值的特殊异常。
如果引发此异常,则将其 value参数用作协程的结果:
@gen.coroutine
def fetch_json(url):
response = yield AsyncHTTPClient().fetch(url)
raise gen.Return(json_decode(response.body))
在 Python 3.3 中,不再需要这个异常:return语句可以直接用于返回一个值(以前 yield和 return不能在同一个函数中组合使用)。
与 return语句类比, value参数是可选的,但从来没有必要引发 gen.Return()。 return语句可以不带参数使用。
在timeout中包装 Future(或其他可产生的对象)。
如果输入future在timeout之前未完成,则引发 tornado.util.TimeoutError,这可以以 IOLoop.add_timeout允许的任何形式指定(即 datetime.timedelta 或相对于 IOLoop.time 的绝对时间)
如果包装的 Future在超时后失败,则将记录异常,除非它是 quiet_exceptions 中包含的类型(可能是异常类型或类型序列)或 asyncio.CancelledError。
当timeout到期时,包装的 Future不会被取消,允许它被重用。 asyncio.wait_for 与此函数类似,但它会在timeout时取消包装的 Future。
在 4.1 版更改: 添加了 quiet_exceptions参数和未处理异常的日志记录。
在 4.4 版更改: 添加了对 Future 以外的可缩性对象的支持。
在 6.0.3 版更改: asyncio.CancelledError 现在总是被认为是“quiet”。
返回在给定秒数后解析的 Future。
当在协程中与 yield一起使用时,这是 time.sleep 的非阻塞模拟(不应在协程中使用,因为它是阻塞的):
yield gen.sleep(0.5)
请注意,单独调用此函数不会执行任何操作; 你必须等待它返回的 Future(通常是通过yielding it)。
提供一个迭代器以在等待对象完成时产生结果。
产生一组像这样的等待对象:
results = yield [awaitable1, awaitable2]
暂停协程,直到 awaitable1和 awaitable2都返回,然后使用两个 awaitables的结果重新启动协程。 如果任一 awaitable引发异常,则表达式将引发该异常并且所有结果都将丢失。
如果你需要尽快得到每个 awaitable的结果,或者如果你需要一些 awaitable的结果,即使是其他的产生错误,你可以使用 WaitIterator:
wait_iterator = gen.WaitIterator(awaitable1, awaitable2)
while not wait_iterator.done():
try:
result = yield wait_iterator.next()
except Exception as e:
print("Error {} from {}".format(e, wait_iterator.current_future))
else:
print("Result {} received from {} at {}".format(
result, wait_iterator.current_future,
wait_iterator.current_index))
因为结果一旦可用就会返回,迭代器的输出与输入参数的顺序不同。 如果您需要知道哪个 future产生了当前结果,您可以使用属性 WaitIterator.current_future 或 WaitIterator.current_index 从输入列表中获取 awaitable的索引。 (如果在 WaitIterator的构造中使用了关键字参数,current_index将使用相应的关键字)。
在 Python 3.5 上,WaitIterator实现了异步迭代器协议,因此它可以与 async for语句一起使用(请注意,在此版本中,如果任何值引发异常,整个迭代都会中止,而前面的示例可以继续过去个别错误):
async for result in gen.WaitIterator(future1, future2):
print("Result {} received from {} at {}".format(
result, wait_iterator.current_future,
wait_iterator.current_index))
如果此迭代器没有更多结果,则返回 True。
返回将产生下一个可用结果的 Future。
请注意,此 Future与任何输入都不是同一个对象。
并行运行多个异步操作。
children可以是一个列表,也可以是一个字典,其值是可产生的对象。multi() 返回一个新的 yieldable对象,该对象解析为包含其结果的并行结构。 如果 children是一个列表,则结果是一个相同顺序的结果列表; 如果是字典,则结果是具有相同键的字典。
也就是说,results = yield multi(list_of_futures) 等价于:
results = []
for future in list_of_futures:
results.append(yield future)
如果任何children引发异常, multi() 将引发第一个异常。 所有其他人都将被记录,除非它们属于 quiet_exceptions 参数中包含的类型。
在基于 yield 的协程中,通常不需要直接调用此函数,因为协程运行程序会在产生列表或字典时自动执行此操作。 但是,在基于 await的协程中是必需的,或者传递 quiet_exceptions参数。
由于历史原因,此函数在名称 multi() 和 Multi() 下可用。
取消 multi() 返回的 Future不会取消其子级。 asyncio.gather类似于 multi(),但它确实取消了它的children。
在 4.2 版更改: 如果多个 yieldable失败,将记录第一个之后的任何异常(引发)。 添加了 quiet_exceptions参数以抑制所选异常类型的此日志记录。
在 4.3 版更改: 用统一的函数 multi替换了类 Multi和函数 multi_future。 添加了对 YieldPoint和 Future以外的支持。
并行等待多个异步future。
从 Tornado 6.0 开始,这个功能和 multi完全一样。
4.0 版中的新功能。
在 4.2 版更改: 如果多个 Futures失败,将记录第一个(引发)之后的任何异常。 添加了 quiet_exceptions参数以抑制所选异常类型的此日志记录。
4.3 版后已弃用:改用 multi。
将产生的对象转换为 Future。
默认实现接受列表、字典和Futures。 这具有启动任何没有自己启动的协程的副作用,类似于 asyncio.ensure_future。
如果可以使用 singledispatch库,则可以扩展此功能以支持其他类型。 例如:
@convert_yielded.register(asyncio.Future)
def _(asyncio_future):
return tornado.platform.asyncio.to_tornado_future(asyncio_future)
将 x 转换为 Future。
如果 x 已经是 Future,则简单地返回它; 否则它会被包裹在一个新的 Future 中。 当您不知道 f() 是否返回 Future 时,这适合用作 result = yield gen.maybe_future(f()) 。
4.3 版后已弃用:此函数仅处理 Futures,而不处理其他可生成对象。 不是 may_future,而是检查您期望的非future结果类型(通常只是 None),并产生任何未知的结果。
返回 func 是否为协程函数,即用coroutine包裹的函数。
一个特殊的对象,可以让 IOLoop 运行一次迭代。
这在正常使用中是不需要的,但它对长时间运行的协程很有帮助,这些协程可能会产生立即准备好的 Futures。
用法:yield gen.moment
在原生协程中,yield gen.moment 等同于 await asyncio.sleep(0)。
4.0 版中的新功能。
4.5 版后已弃用:yield None(或没有参数的 yield)现在等同于 yield gen.moment。