我已经使用 Python 多年,但只是逐渐研究了这门语言的一些比较晦涩的特性,因为我的大部分代码都是用于数据处理的。基于 yield
的生成器是我日常工具包的一部分,最近我阅读了有关协程的内容。我找到了一个类似的例子:
def averager():
sum = 0.0
n = 0
while True:
value = yield
sum += value
n += 1
print(sum/n)
avg = averager()
next(avg) # prime the coroutine
avg.send(3)
avg.send(4)
avg.send(5)
它打印发送给它的值的平均值。我认为这样的东西可能对数据处理管道有用,所以我决定把它放在脑后。也就是说,直到我在 Python documentation 中阅读以下通知:
Support for generator-based coroutines is deprecated and is scheduled for removal in Python 3.10.
显然我想编写面向 future 的代码,所以在这一点上开始学习基于生成器的协程可能没有用。那么,我的问题是:如何使用原生 (asyncio
) 协程来实现这个示例?我很难理解原生协程语法。
在尝试搜索答案时,我找到了一个 related question它有一个 comment和一个 answer这基本上是在说“你不能用 async
来做,而是用 yield
为基础的协程来做”。但是,如果这些都消失了,在 3.10+ 中是否有任何方法可以使用协程来做到这一点?
最佳答案
来了Asynchronous Generators ...
所以我们在异步上下文中仍然拥有那种力量。
至于理论 - 提到的 PEP 525 提供了很好的描述,绝对值得一读。
我将发布一个准备好的说明性示例(用于异步 averager
),包括初始化和安全终结:
import asyncio
async def coro():
print('running other coroutine in 3 sec ...')
await asyncio.sleep(3) # emulate working
async def averager():
sum_ = n = 0
while True:
v = yield
sum_ += v
n += 1
print(sum_ / n)
await asyncio.sleep(0.1)
async def main():
agen = averager()
await agen.asend(None)
print(agen.__name__, 'initialized ...')
await agen.asend(3)
print('another separate processing here ...')
await coro()
await agen.asend(4)
await agen.asend(14)
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main())
finally:
loop.run_until_complete(loop.shutdown_asyncgens())
loop.close()
程序输出:
averager initialized ...
3.0
another separate processing here ...
running other coroutine in 3 sec ...
3.5
7.0
关于python - 从基于生成器的协程转换为 native 协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58658305/