【问题标题】:Why are generator-based coroutines consumes, asynchronous generators asynchronous data producers, and coroutines asynchronous data consumers?为什么基于生成器的协程消费,异步生成器异步数据生产者,协程异步数据消费者?
【发布时间】:2018-03-31 00:42:45
【问题描述】:
来自 Jim Fasarakis Hilliard 的 a comment:
生成器:def 包含一个或多个 yield 表达式的函数。
生成器用作数据生产者(它们yield 值)。
我能理解。
基于生成器的协程:由types.coroutine 包装的生成器 (def + yield)。你需要把它包起来
types.coroutine 如果您需要将其视为协程对象。
基于生成器的协程被用作消费者(你 .send 值
他们或他们yield from的子生成器。
“消费者(您.send 重视他们或他们yield from 的子生成器)”是什么意思?
异步生成器:async def 函数包含一个或多个 yield 表达式。这些也可以包含await 表达式。
异步生成器是异步数据生产者。
“异步数据生产者”是什么意思?
协程:async def 没有零个或多个 awaits,也没有 yields。
协程是异步数据消费者。
“异步数据消费者”是什么意思?
谢谢。
【问题讨论】:
标签:
python
python-3.x
asynchronous
generator
coroutine
【解决方案1】:
在 python 中,生成器现在以多种方式使用。 生成器的最初目的是暂停执行,然后将 yield 一个值返回给调用者。然后调用者可以稍后调用 next 来恢复生成器。因此生成器是数据生产者。
现在以上版本的生成器只允许通过yield 语句返回数据。现在,要使函数成为协程,它还应该接受来自调用者的值。因此,PEP 342 在 python 2.5 中被引入以增强生成器,以便它们可以充当完整的协同程序。这允许调用者向生成器发送值。
现在的新问题是,当重构生成器并且您希望将其部分操作委托给子生成器时,您需要将子生成器显式调用为迭代器,传播调用者发送的数据并处理异常。为了简化子生成器的操作,PEP 380 中定义了一个新操作 yield from 作为 python 3.3 的一部分。 yield from 在语法上比普通的 yield 语法要多得多。在一个完美的世界中,可能会使用一个新的关键字。
现在的问题是生成器在两种不同的环境中使用。作为迭代器和协程。如果可以将生成器显式定义为协程,那就更好了。因此 Python 3.5 中的 PEP 492 introduced async and await 关键字。因此,任何用作协程的生成器都由 async 关键字指示。 Python 3.5 中的协程可以使用await 关键字代替yield from。请注意,从 python 3.5 开始,协程是不同的类型!!
现在假设您有一个带有def 和yield 的生成器函数。您可以使用 types.coroutine 装饰器将现有的生成器类型转换为协程类型。这些消费者可以通过send() 接受值并使用yield from 将其委托给子生成器。
在python 3.5中,可以使用async来表示该函数是协程类型。这样的函数可以包含普通的yield 和await。它们不能包含yield from(因为await 替换了该功能)。当协程包含普通的yield 时,它们是生成器调用链中最低的,因此称为异步数据生产者。
任何没有纯yield 的协程都将成为数据消费者,因为它必须通过await 调用另一个协程来获取异步数据。