我正在从旧式协程过渡(其中“yield”返回“send”提供的值,但是
本质上是生成器)到带有“async def”和“await”的新型协程。
有几件事确实让我困惑。
考虑以下旧式协程,它计算提供给的数字的运行平均值
它通过“发送”,在每个点返回到目前为止的平均值。 (这个例子来自《流利
Python作者:卢西亚诺·拉马略。)
def averager():
total = 0.0
count = 0
average = None
while True:
term = yield average
total += term
count += 1
average = total/count
如果我现在创建并启动一个协程对象,我可以向它发送数字,它将返回正在运行的
平均的:
>>> coro_avg = averager()
>>> next(coro_avg)
>>> coro_avg.send(10)
10.0
>>> coro_avg.send(30)
20.0
>>> coro_avg.send(5)
15.0
...等等。问题是,这样的协程如何用async/await来写呢?那里
有三点让我困惑。我对它们的理解正确吗?
1) 在旧方式中,任何人都可以将数字发送到平均器的同一实例。我可以通过
在上面的值 coro_avg 周围,每次调用 .send(N) 时,无论从哪里,N 都会添加到同一个运行中
全部的。然而,使用 async/await 时,无法“发送值”。每次你“等待”一个
在协程中,您等待一个具有自己的上下文和变量值的新实例。
2)似乎“async def”协程将值返回给正在等待的事物的唯一方法
它是“返回”,因此失去了上下文。您不能从“异步”内部调用“yield”
def' 协程(或者更确切地说,如果你这样做了,你已经创建了一个异步生成器
不能与await 一起使用)。因此“async def”协程无法计算值和手
就像平均器一样,在保持上下文的同时将其输出。
3) 与 (1) 几乎相同:当协程调用“await”时,它会等待单个特定的可等待对象,
即等待的参数。这与旧式协程非常不同,旧式协程放弃控制并
坐着等待anyone发送一些东西给他们。
我意识到新的协程是与旧的协程不同的编码范例:它们被使用
使用事件循环,您可以使用队列等数据结构让协程发出一个值,而无需
返回和失去上下文。新的和旧的共享相同的东西,这有点不幸,也有点令人困惑
名称——协程——因为它们的调用/返回协议是如此不同。