在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的成就,以及这两种机制之间的区别。
答案 0 :(得分:22)
两者之间存在巨大差异。 yield from
需要另一台发电机并继续从该发电机中产生(委托责任,因为它)。 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
生成器委派语法。
因此,Tornado必须对@tornado.gen.coroutine
生成器产生的值进行后处理,以检测是否产生了tornado.concurrent.Future
个对象; @asyncio.coroutine
代码处理可以更简单。事实上,Tornado Runner.run()
method会进行显式类型检查以处理委派任务。