在 Tornado 中,我们通常会编写如下代码来异步调用函数:
class MainHandler(tornado.web.RequestHandler):
@tornado.gen.coroutine
def post(self):
...
yield self.handleRequest(foo)
...
@tornado.gen.coroutine
def handleRequest(self, foo):
...
但是在 asyncio(将随 Python 3.4 一起提供,可以从 Python 3.3 的 pip 安装)中,我们使用 yield from
来实现相同的目的:
@asyncio.coroutine
def myPostHandler():
...
yield from handleRequest(foo)
...
@asyncio.coroutine
def handleRequest(foo)
...
从代码上看,区别是yield
和yield from
。但是前者的 handleRequest(foo)
返回一个 tornado.concurrent.Future
对象,后者返回一个 generator
对象。
我的问题是,这两个东西在机制上有什么区别?控制流程如何?谁调用实际的 handleRequest
并检索其返回值?
附加:我对 Python 生成器和迭代器有基本的了解。我想了解 Tornado 和 asyncio 通过使用这些实现了什么,以及这两种机制之间有什么区别。
最佳答案
两者之间存在巨大差异。 yield from
获取另一个生成器并继续从该生成器产生(委托(delegate)责任,就像它一样)。 yield
只产生 一个 值。
换句话说,yield from
,在最简单的情况下,可以替换为:
for value in self.handleRequest(foo):
yield value
如果您更换了 yield from <expression>
符合 yield <expression>
您会将整个生成器返回给调用者,而不是生成器生成的值。
yield from
语法仅在 Python 3.3 中引入,见 PEP 380: Syntax for Delegating to a Subgenerator .除了 Python 3.3 之外,Tornado 还支持 Python 版本 2.6、2.7 和 3.2,因此它不能依赖 yield from
语法可用。 asyncio
另一方面,作为 3.4 中添加的核心 Python 库,可以完全依赖 yield from
生成器委托(delegate)语法可用。
因此,Tornado 将不得不对 @tornado.gen.coroutine
产生的值进行后处理。生成器来检测 tornado.concurrent.Future
对象已产生; @asyncio.coroutine
代码处理可以简单得多。确实是Tornado Runner.run()
method执行显式类型检查以处理委派任务。
关于python - Tornado的 "yield"和asyncio的 "yield from"在机制上的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21021498/