tornado.gen
— 基于生成器的协程¶
tornado.gen
实现基于生成器的协程。
注意
本模块中的“装饰器和生成器”方法是原生协程(使用 async def
和 await
)的前身,原生协程在 Python 3.5 中引入。不需要与旧版 Python 保持兼容的应用程序应该使用原生协程。本模块的某些部分在使用原生协程时仍然有用,尤其是 multi
、sleep
、WaitIterator
和 with_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 中的异步函数返回一个 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
对象。有关扩展此机制的信息,请参见 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
语句直接返回值(以前yield
和return
无法在同一个函数中组合使用)。根据 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.TimeoutError
,timeout
可以用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]
会暂停协程,直到
awaitable1
和awaitable2
都返回,然后使用两个可等待对象的结果重新启动协程。如果任一可等待对象引发异常,表达式将引发该异常,并且所有结果都将丢失。如果您需要尽快获取每个可等待对象的结果,或者即使其他可等待对象产生错误,也需要某些可等待对象的结果,则可以使用
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
获取可等待对象在输入列表中的索引(如果在构造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
支持。
- 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.gather
与multi()
类似,但它会取消其子项。在 4.2 版本中变更: 如果多个可 yield 对象失败,则记录第一个(已引发)异常之后的任何异常。添加了
quiet_exceptions
参数以抑制对选定异常类型的此日志记录。在 4.3 版本中变更: 用统一函数
multi
替换了类Multi
和函数multi_future
。添加了对除YieldPoint
和Future
之外的可 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
。