Skip to main content

tornado.gen —简化异步代码

tornado.gen 是一个基于发生器的接口,使它更容易在异步环境中工作。使用 gen 模块的代码在技术上是异步的,但它被写为单个生成器,而不是单独函数的集合。

例如,以下异步处理程序:

class AsyncHandler(RequestHandler):
    @asynchronous
    def get(self):
        http_client = AsyncHTTPClient()
        http_client.fetch("http://example.com",
                          callback=self.on_fetch)

    def on_fetch(self, response):
        do_something_with_response(response)
        self.render("template.html")

可以用 gen 编写:

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中的大多数异步函数返回 Future;产生这个对象返回它的 result

您还可以生成 Futures 的列表或字典,它将同时启动并并行运行;当结果全部完成后,将返回结果的列表或字典:

@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']

如果 singledispatch 库可用(Python 3.4中的标准,通过旧版本的 单独分派 包可用),可能会产生其他类型的对象。当导入 tornado.platform.asynciotornado.platform.twisted 时,Tornado包括对 asyncio.Future 和Twisted的 Deferred 类的支持。参见 convert_yielded 功能来扩展此机制。

在 3.2 版更改: 添加了Dict支持。

在 4.1 版更改: 支持通过 singledispatch 添加到产生 asyncio Futures和Twisted Deferred。

装饰

tornado.gen.coroutine(func, replace_callback=True)[源代码]

异步发生器的装饰器。

任何从这个模块产生对象的生成器都必须包装在这个装饰器或 engine 中。

协同程序可以通过提出特殊异常 Return(value) “返回”。在Python 3.3+中,函数也可以简单地使用 return value 语句(在Python 3.3之前,不允许生成器也返回值)。在Python的所有版本中,只希望提前退出的协程可以使用没有值的 return 语句。

这个装饰器的函数返回一个 Future。此外,它们可以使用 callback 关键字参数调用,它将在解析时使用未来的结果调用。如果协程失败,回调将不会运行,并且异常将引发到周围的 StackContext 中。 callback 参数在修饰函数内部不可见;它由装饰器本身处理。

从呼叫者的角度来看,@gen.coroutine 类似于 @return_future@gen.engine 的组合。

警告

当异常发生在协程中时,异常信息将存储在 Future 对象中。您必须检查 Future 对象的结果,否则代码可能会忽略异常。这意味着如果从另一个协同程序调用,则使用 IOLoop.run_sync 来调用顶级调用,或者将 Future 传递给 IOLoop.add_future

tornado.gen.engine(func)[源代码]

异步生成器的回调导向装饰器。

这是一个旧的接口;对于不需要与3.0以前的Tornado版本兼容的新代码,建议使用 coroutine 装饰器。

这个装饰器类似于 coroutine,除了它不返回 Futurecallback 参数不被特殊处理。

在大多数情况下,用 engine 装饰的函数应该使用 callback 参数,并在完成后用其结果调用它。一个值得注意的例外是 RequestHandler HTTP动词方法,它使用 self.finish() 代替回调参数。

效用函数

exception tornado.gen.Return(value=None)[源代码]

coroutine 返回值的特殊例外。

如果引发此异常,其值参数将用作协同程序的结果:

@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, future, io_loop=None, quiet_exceptions=())[源代码]

在超时中包装 Future (或其他可伸缩对象)。

如果输入未来在 timeout 之前未完成,则提高 TimeoutError,其可以以 IOLoop.add_timeout 允许的任何形式指定(即 datetime.timedelta 或相对于 IOLoop.time 的绝对时间)

如果被包装的 Future 在超时后失败,则将记录该异常,除非它是 quiet_exceptions 中包含的类型(其可以是异常类型或类型序列)。

不支持 YieldPoint 子类。

4.0 新版功能.

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

在 4.4 版更改: 添加对除 Future 之外的可伸缩对象的支持。

exception tornado.gen.TimeoutError[源代码]

with_timeout 提出的异常。

tornado.gen.sleep(duration)[源代码]

返回在给定秒数后解析的 Future

当在协程中与 yield 一起使用时,这是与 time.sleep 的非阻塞类似(不应在协同程序中使用,因为它是阻塞的):

yield gen.sleep(0.5)

注意,调用这个函数本身不起作用;你必须等待它返回的 Future (通常通过产生它)。

4.1 新版功能.

tornado.gen.moment

可以产生以允许IOLoop运行一次迭代的特殊对象。

这在正常使用中不需要,但它可能有助于长期运行的协同程序,可能产生立即就绪的期货。

用法:yield gen.moment

4.0 新版功能.

class tornado.gen.WaitIterator(*args, **kwargs)[源代码]

提供一个迭代器,在期货结束时产生期货的结果。

产生一套这样的期货:

results = yield [future1, future2]

暂停协程,直到 future1future2 返回,然后使用两个期货的结果重新启动协同程序。如果两个future都是一个异常,表达式将引发异常,所有的结果都将丢失。

如果你需要尽快得到每一个未来的结果,或者如果你需要一些期货的结果,即使其他人产生错误,你可以使用 WaitIterator:

wait_iterator = gen.WaitIterator(future1, future2)
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))

因为结果一旦可用,就返回迭代器 将不会与输入参数的顺序相同 的输出。如果需要知道哪个未来生成当前结果,您可以使用属性 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()[源代码]

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

next()[源代码]

返回将产生下一个可用结果的 Future

请注意,此 Future 将不是与任何输入相同的对象。

tornado.gen.multi(children, quiet_exceptions=())[源代码]

并行运行多个异步操作。

children 可以是列表或其值是可生成对象的dict。 multi() 返回一个新的可析出对象,该对象解析为包含其结果的并行结构。如果 children 是列表,则结果是以相同顺序的结果的列表;如果它是一个dict,结果是一个dict与相同的键。

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

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

如果任何儿童提出例外,multi() 将提出第一个。所有其他都将被记录,除非它们是包含在 quiet_exceptions 参数中的类型。

如果任何输入是 YieldPoints,则返回的可伸缩对象是 YieldPoint。否则,返回 Future。这意味着 multi 的结果可以在本地协同程序中使用,当且仅当它的所有子代都可以。

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

由于历史原因,此功能在名称 multi()Multi() 下可用。

在 4.2 版更改: 如果多个yieldable失败,则将记录第一个(引发的)之后的任何异常。添加了 quiet_exceptions 参数以禁止所选异常类型的此日志记录。

在 4.3 版更改: 用统一的函数 multi 替换类 Multi 和函数 multi_future。增加了对 YieldPointFuture 之外的yieldables的支持。

tornado.gen.multi_future(children, quiet_exceptions=())[源代码]

等待多个异步期货并行。

此功能与 multi 类似,但不支持 YieldPoints

4.0 新版功能.

在 4.2 版更改: 如果多个 Futures 失败,则将记录第一个(引发的)之后的任何异常。添加了 quiet_exceptions 参数以禁止所选异常类型的此日志记录。

4.3 版后已移除: 请改用 multi

tornado.gen.Task(func, *args, **kwargs)[源代码]

适应用于协同程序的基于回调的异步函数。

获取一个函数(和可选的附加参数),并使用这些参数加上一个 callback 关键字参数来运行它。传递给回调的参数作为yield表达式的结果返回。

在 4.0 版更改: gen.Task 现在是返回 Future 的函数,而不是 YieldPoint 的子类。它仍然表现相同的方式,当产生。

class tornado.gen.Arguments

TaskWait 的结果,其回调具有多个参数(或关键字参数)。

Arguments 对象是 collections.namedtuple,并且可以用作元组 (args, kwargs) 或具有属性 argskwargs 的对象。

tornado.gen.convert_yielded(*args, **kw)[源代码]

将生成的对象转换为 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)[源代码]

x 转换为 Future

如果 x 已经是 Future,则它被简单地返回;否则它被包裹在一个新的 Future。当您不知道 f() 是否返回 Future 时,这适合用作 result = yield gen.maybe_future(f())

4.3 版后已移除: 此函数仅处理 Futures,而不处理其他可伸缩对象。而不是 maybe_future,检查您期望的非未来结果类型(通常只是 None),并且 yield 任何未知的结果类型。

传统接口

在Tornado 3.0中引入 Futures 的支持之前,协程在其 yield 表达式中使用 YieldPoint 的子类。这些类仍然受支持,但通常不应使用,除了与旧接口的兼容性。这些类都不与本机(基于 await 的)协同程序兼容。

class tornado.gen.YieldPoint[源代码]

可以从生成器生成的对象的基类。

4.0 版后已移除: 请改用 Futures

start(runner)[源代码]

在发电机输出后由转轮调用。

start 之前,不会对此对象调用其他方法。

is_ready()[源代码]

由跑步者调用以确定是否恢复发电机。

返回布尔值;可以被称为多于一次。

get_result()[源代码]

返回用作yield表达式的结果的值。

这个方法将只被调用一次,并且只有在 is_ready 返回true之后。

class tornado.gen.Callback(key)[源代码]

返回将允许匹配的 Wait 继续的可调用对象。

密钥可以是适于用作字典密钥的任何值,并且用于将 Callbacks 与其相应的 Waits 相匹配。在发生器函数的单个运行中,键必须是唯一的,但是可以在同一函数的不同运行中重用(因此常量通常工作正常)。

回调可以用零或一个参数调用;如果给出参数,它将由 Wait 返回。

4.0 版后已移除: 请改用 Futures

class tornado.gen.Wait(key)[源代码]

返回传递给前一个 Callback 的结果的参数。

4.0 版后已移除: 请改用 Futures

class tornado.gen.WaitAll(keys)[源代码]

返回多个先前 Callbacks 的结果。

参数是 Callback 键的序列,结果是以相同顺序的结果列表。

WaitAll 等效于产生 Wait 对象的列表。

4.0 版后已移除: 请改用 Futures

class tornado.gen.MultiYieldPoint(children, quiet_exceptions=())[源代码]

并行运行多个异步操作。

这个类类似于 multi,但它总是创建一个堆栈上下文,即使没有孩子需要它。它与本地协同程序不兼容。

在 4.2 版更改: 如果多个 YieldPoints 失败,则将记录第一个(引发的)之后的任何异常。添加了 quiet_exceptions 参数以禁止所选异常类型的此日志记录。

在 4.3 版更改: Multi 更名为 MultiYieldPoint。名称 Multi 仍保留为等效 multi 函数的别名。

4.3 版后已移除: 请改用 multi