我已经使用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中阅读了以下通知:
不支持基于生成器的协程,并计划在Python 3.10中删除。
很明显,我想编写面向未来的代码,因此在这一点上开始学习基于生成器的协程可能没有用。那么,我的问题是:如何使用本机(asyncio
)协程实现该示例?我要花很多时间来围绕本机协程语法。
在尝试寻找答案时,我发现了一个related question和一个comment和一个answer,它们基本上说“您无法使用{{1} },而是改为使用基于async
的协程”。但是,如果这些都消失了,那么有什么办法可以在3.10+中使用协程吗?
答案 0 :(得分:1)
然后有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