【问题标题】:Generator-based coroutine versus native coroutine基于生成器的协程与原生协程
【发布时间】:2015-12-11 12:05:30
【问题描述】:

我刚刚读到 PEP0492 谈论协程的新方法,但 PEP 未能让我理解基于生成器的协程和本地协程之间的区别。谁能告诉我区别(也许有例子)?

据我了解,他们使用不同的词(yield/yield from 和 await/async/yield)。我知道在原生协程结束时会产生一个收益,但这也适用于基于生成器的协程。

【问题讨论】:

  • 区别在于语法;它是语法糖,使其更清晰。
  • 那么,除了语法之外,它们是相同的吗?听起来太奇怪了……它不会在 PEP 中获得批准。
  • 装饰器也是语法糖,你可以在函数声明之后使用func = decorator(func)。上下文管理器是try:...except:...finally: 的语法糖。 Python 是关于可读性和目的明确性的,这完全符合这些目标。
  • 这样说,似乎更合法。做出回答,我会接受的

标签: python async-await coroutine python-3.5


【解决方案1】:

扩展 Mike S 所写的内容:CPython 中的原生协程与生成器共享大部分代码,因此在功能上几乎没有区别。但是,我认为 PEP-492 超出了“语法糖”的门槛。生成器和原生协程有不同的用途,因此新语法阐明了作者的意图,并且可以做旧语法不能做的事情。下面是一些例子:

  • 生成器是可迭代的,而原生协程不是。
  • 原生协程还允许使用异步上下文管理器和异步迭代器等新语法。
  • 协程具有有用的调试消息,例如如果您从不 await 协程对象,则会发出警告。

新语法也很好地反映了asyncio 库,并且类似于其他语言中使用的关键字。

【讨论】:

  • [docs.python.org/3/reference/expressions.html#yield-expressions) 是,并且一直是,表达式 await 不能在任何地方使用 yield from 不能。事实上,区别恰恰相反:yield from 可以用在await 不能使用的地方——即非async 函数(这种限制有时有助于捕获错误)。
  • 谢谢@abarnert。你绝对是对的。我已经从我的回答中删除了那个不正确的陈述。
  • @MarkE.Haase 我会说幕后的原生协程是基于生成器的吗?
  • @EngineerSpock 是的
【解决方案2】:

没有功能区别。使用 asyncawait 关键字的“原生协程”只是之前在“基于生成器的协程”中实现的语法糖。

3.5 docs中推荐使用asyncawait如果不需要支持旧的Python版本

【讨论】:

    【解决方案3】:

    嗯,通常编写协程的方式涉及回调。尽管回调最初可能很方便,但在我看来,它们会导致高度复杂和复杂的代码,至少可以说这不是 Pythonic。此外,yield(尤其是从 python 3.3 开始的yield from),让协程的实现变得更加容易和 Python 化。

    使用生成器,您可以轻松地将代码分为初始部分和回调。

    @asyncio.coroutine
    def print_sum(x, y):
        result = yield from compute(x, y)
    
        #write callback code
        print("%s + %s = %s" % (x, y, result))
    

    【讨论】:

    • 好的,但这并不能回答“原生协程和基于生成器的协程有何不同?”的问题
    • 它们不...只是实现相同事物的不同方式
    猜你喜欢
    • 2020-02-27
    • 2017-02-06
    • 2017-09-02
    • 2018-03-13
    • 2023-03-05
    • 2018-10-14
    • 2011-08-22
    • 2017-06-04
    • 2014-02-27
    相关资源
    最近更新 更多