tornado.gen — 基于生成器的协程

tornado.gen 实现基于生成器的协程。

注意

本模块中的“装饰器和生成器”方法是原生协程(使用 async defawait)的前身,原生协程在 Python 3.5 中引入。不需要与旧版 Python 保持兼容的应用程序应该使用原生协程。本模块的某些部分在使用原生协程时仍然有用,尤其是 multisleepWaitIteratorwith_timeout。这些函数中的一些在 asyncio 模块中也有对应的函数,也可以使用,尽管两者不一定完全兼容。

与连接回调相比,协程提供了一种更轻松的方法来处理异步环境。使用协程的代码在技术上是异步的,但它被编写为单个生成器而不是一组单独的函数。

例如,以下是一个基于协程的处理程序

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 中的异步函数返回一个 AwaitableFuture;生成此对象将返回其结果。

您也可以生成其他可生成对象的列表或字典,这些对象将同时启动并并行运行;结果列表或字典将在它们全部完成时返回

@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 对象。有关扩展此机制的信息,请参见 convert_yielded 函数。

版本 3.2 中的变更: 添加了对字典的支持。

版本 4.1 中的变更: 通过 singledispatch 添加了对生成 asyncio Future 和 Twisted Deferred 的支持。

装饰器

tornado.gen.coroutine(func: Callable[[...], Generator[Any, Any, _T]]) Callable[[...], Future[_T]][source]
tornado.gen.coroutine(func: Callable[[...], _T]) Callable[[...], Future[_T]]

异步生成器的装饰器。

为了与旧版 Python 保持兼容性,协程也可以通过引发特殊异常 Return(value) 来“返回”。

使用此装饰器的函数返回一个 Future

警告

当协程内部发生异常时,异常信息将存储在 Future 对象中。您必须检查 Future 对象的结果,否则异常可能会被您的代码忽略。这意味着从另一个协程中生成该函数,使用类似于 IOLoop.run_sync 的方法进行顶级调用,或将 Future 传递给 IOLoop.add_future

版本 6.0 中的变更: 已删除 callback 参数。改为使用返回的可等待对象。

exception tornado.gen.Return(value: Optional[Any] = None)[source]

coroutine 返回值的特殊异常。

如果引发了此异常,其 value 参数将用作协程的结果

@gen.coroutine
def fetch_json(url):
    response = yield AsyncHTTPClient().fetch(url)
    raise gen.Return(json_decode(response.body))

在 Python 3.3 中,此异常不再需要:可以使用 return 语句直接返回值(以前 yieldreturn 无法在同一个函数中组合使用)。

根据 return 语句的类比,value 参数是可选的,但永远不需要 raise gen.Return()。可以使用不带参数的 return 语句。

工具函数

tornado.gen.with_timeout(timeout: Union[float, datetime.timedelta], future: Yieldable, quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())[source]

用超时时间包装一个 Future(或其他可 yield 的对象)。

如果输入的 future 在 timeout 时间内没有完成,则抛出 tornado.util.TimeoutErrortimeout 可以用 IOLoop.add_timeout 允许的任何形式指定(例如 datetime.timedelta 或相对于 IOLoop.time 的绝对时间)。

如果包装的 Future 在超时后失败,则会记录异常,除非异常类型包含在 quiet_exceptions 中(可以是异常类型或类型序列),或者是一个 asyncio.CancelledError

当超时时间到期时,包装的 Future 不会被取消,允许它被重复使用。 asyncio.wait_for 与此函数类似,但它会在超时时取消包装的 Future

在 4.0 版本中新增。

在 4.1 版本中变更: 添加了 quiet_exceptions 参数和未处理异常的日志记录。

在 4.4 版本中变更: 添加了对除 Future 之外的可 yield 对象的支持。

在 6.0.3 版本中变更: asyncio.CancelledError 现在始终被视为“静默”。

在 6.2 版本中变更: tornado.util.TimeoutError 现在是 asyncio.TimeoutError 的别名。

tornado.gen.sleep(duration: float) Future[None][source]

返回一个在指定秒数后解析的 Future

在协程中与 yield 一起使用时,这是 time.sleep 的非阻塞模拟(不应在协程中使用 time.sleep,因为它会阻塞)。

yield gen.sleep(0.5)

注意,单独调用此函数不会做任何事情;您必须等待它返回的 Future(通常通过 yield 它)。

在 4.1 版本中新增。

class tornado.gen.WaitIterator(*args: Future, **kwargs: Future)[source]

提供一个迭代器,用于在可等待对象完成时 yield 其结果。

像这样 yield 一组可等待对象:

results = yield [awaitable1, awaitable2]

会暂停协程,直到 awaitable1awaitable2 都返回,然后使用两个可等待对象的结果重新启动协程。如果任一可等待对象引发异常,表达式将引发该异常,并且所有结果都将丢失。

如果您需要尽快获取每个可等待对象的结果,或者即使其他可等待对象产生错误,也需要某些可等待对象的结果,则可以使用 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_futureWaitIterator.current_index 获取可等待对象在输入列表中的索引(如果在构造 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))

在 4.1 版本中新增。

在 4.3 版本中变更: 在 Python 3.5 中添加了 async for 支持。

done() bool[source]

如果此迭代器没有更多结果,则返回 True。

next() Future[source]

返回一个 Future,它将 yield 下一个可用结果。

注意,此 Future 不会与任何输入相同。

tornado.gen.multi(Union[List[Yieldable], Dict[Any, Yieldable]], quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())[source]

并行运行多个异步操作。

children 可以是列表或字典,其值为可 yield 的对象。 multi() 返回一个新的可 yield 对象,该对象解析为包含其结果的并行结构。如果 children 是列表,则结果是按相同顺序排列的结果列表;如果它是字典,则结果是具有相同键的字典。

也就是说,results = yield multi(list_of_futures) 等同于

results = []
for future in list_of_futures:
    results.append(yield future)

如果任何子项引发异常,multi() 将引发第一个异常。所有其他异常将被记录,除非它们是 quiet_exceptions 参数中包含的类型。

yield 驱动的协程中,通常不需要直接调用此函数,因为协程运行器会在 yield 列表或字典时自动执行它。但是,在 await 驱动的协程中,或者要传递 quiet_exceptions 参数,这是必要的。

出于历史原因,此函数可以使用 multi()Multi() 两个名称。

取消 multi() 返回的 Future 不会取消其子项。 asyncio.gathermulti() 类似,但它会取消其子项。

在 4.2 版本中变更: 如果多个可 yield 对象失败,则记录第一个(已引发)异常之后的任何异常。添加了 quiet_exceptions 参数以抑制对选定异常类型的此日志记录。

在 4.3 版本中变更: 用统一函数 multi 替换了类 Multi 和函数 multi_future。添加了对除 YieldPointFuture 之外的可 yield 对象的支持。

tornado.gen.multi_future(Union[List[Yieldable], Dict[Any, Yieldable]], quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())[source]

并行等待多个异步 Future。

从 Tornado 6.0 开始,此函数与 multi 完全相同。

在 4.0 版本中新增。

版本 4.2 中的变更: 如果多个 Futures 失败,第一个(被抛出)之后的任何异常都将被记录。添加了 quiet_exceptions 参数,以抑制对所选异常类型的此记录。

版本 4.3 起弃用: 使用 multi 替代。

tornado.gen.convert_yielded(yielded: Union[None, Awaitable, List[Awaitable], Dict[Any, Awaitable], Future]) Future[source]

将一个产生的对象转换为 Future

默认实现接受列表、字典和 Future。这有一个副作用,即启动任何没有自行启动的协程,类似于 asyncio.ensure_future

如果 singledispatch 库可用,则可以扩展此函数以支持其他类型。例如

@convert_yielded.register(asyncio.Future)
def _(asyncio_future):
    return tornado.platform.asyncio.to_tornado_future(asyncio_future)

在 4.1 版本中新增。

tornado.gen.maybe_future(x: Any) Future[source]

x 转换为 Future

如果 x 已经是 Future,则直接返回;否则将其包装在一个新的 Future 中。这适合用作 result = yield gen.maybe_future(f()),当您不知道 f() 是否返回 Future 时。

版本 4.3 起弃用: 此函数仅处理 Futures,不处理其他可产生对象。代替使用 maybe_future,检查您期望的非 Future 结果类型(通常只是 None),并 yield 任何未知的类型。

tornado.gen.is_coroutine_function(func: Any) bool[source]

返回 func 是否为协程函数,即用 coroutine 包装的函数。

版本 4.5 中的新功能。

tornado.gen.moment

一个特殊对象,可以生成它以允许 IOLoop 运行一次迭代。

在正常使用中不需要此对象,但在可能生成已准备好立即完成的 Future 的长时间运行的协程中它可能很有帮助。

用法:yield gen.moment

在原生协程中,yield gen.moment 的等效项是 await asyncio.sleep(0)

在 4.0 版本中新增。

版本 4.5 起弃用: yield None(或没有参数的 yield)现在等效于 yield gen.moment