【问题标题】:Difference between "yield" of Tornado and "yield from" of asyncio in mechanism?Tornado 的“yield”和 asyncio 的“yield from”在机制上的区别?
【发布时间】:2014-01-28 01:54:08
【问题描述】:

在 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)
    ...

从代码上看,区别是yieldyield from。但是前者handleRequest(foo)返回一个tornado.concurrent.Future对象,后者返回一个generator对象。

我的问题是,这两个东西在机制上有什么区别?控制流程如何?谁调用实际的handleRequest 并检索其返回值?

附加:我对 Python 生成器和迭代器有基本的了解。我想了解 Tornado 和 asyncio 通过使用这些实现了什么,以及这两种机制之间有什么区别。

【问题讨论】:

    标签: python generator tornado yield


    【解决方案1】:

    两者之间存在巨大差异。 yield from 采用另一个生成器并继续从该生成器产生(委托责任,就像它一样)。 yield 只产生 一个 值。

    换句话说,yield from,在最简单的情况下,可以替换为:

    for value in self.handleRequest(foo):
        yield value
    

    如果你用yield <expression> 替换了yield from <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 会进行显式类型检查来处理委派任务。

    【讨论】:

    • 感谢您的快速回复。但我的问题与yield 本身无关。我担心 Tornado 和 asyncio 使用 yieldyield from 实现了什么。
    • @StarBrilliant:他们实现了将任务推迟到以后;生成器可以暂停,以便事件循环可以将控制权传递给另一个生成器。
    • @StarBrilliant:协程运行器将循环通过活动的协程并给每个协程执行的机会。然后,需要等待网络资源的协程可以立即再次让步,以允许将控制权传递给其他可能不必等待的协程。
    • @StarBrilliant:但您的问题似乎是关于语法差异; yield from 使运行器代码更简单; tornado 必须使用显式包装器来处理委托,asyncio 可以依靠语法来处理委托。
    • 除了使运行器更简单之外,yield from 也更快,并且在出现错误时往往会产生更好的堆栈跟踪。另一方面,Tornado 对yield 的使用提供了协程和非协程之间更好的互操作性(包括带有显式回调的异步逻辑和线程执行器)。
    猜你喜欢
    • 2014-01-10
    • 2016-06-01
    • 2014-11-11
    • 2014-04-22
    • 2016-09-08
    • 2018-01-19
    • 2018-06-03
    • 1970-01-01
    • 2020-05-30
    相关资源
    最近更新 更多