我无法理解Python 3.6中引入的异步理解的使用。作为免责声明,我在Python中一般没有处理异步代码的经验。
what's new for Python 3.6文档中给出的示例是:
result = [i async for i in aiter() if i % 2]
在PEP中,这扩展为:
result = []
async for i in aiter():
if i % 2:
result.append(i)
我认为我理解aiter()
函数是异步调用的,因此aiter
的每次迭代都可以继续进行,而前一个函数不必返回(或者是这种理解)错?)。
我不确定的是,这将如何转化为此处的列表理解。结果是按照返回的顺序放入列表中的吗?或者在最终列表中是否有有效的“占位符”,以便每个结果都以正确的顺序放在列表中?或者我是否以错误的方式思考这个问题?
此外,是否有人能够提供一个真实的示例来说明适用的用例和async
这样的理解中的基本机制?
答案 0 :(得分:20)
您基本上是在询问async for
循环如何在常规循环中运行。你现在可以在列表理解中使用这样的循环并没有任何区别;这只是一种避免重复list.append()
次调用的优化,就像普通列表理解一样。
然后,async for
循环只是等待迭代协议的每个下一步,其中常规for
循环将阻塞。
为了说明,设想一个正常的for
循环:
for foo in bar:
...
对于这个循环,Python实际上是这样做的:
bar_iter = iter(bar)
while True:
try:
foo = next(bar_iter)
except StopIteration:
break
...
next(bar_iter)
调用不是异步的;它阻止。
现在将for
替换为async for
,以及Python所做的更改为:
bar_iter = aiter(bar) # aiter doesn't exist, but see below
while True:
try:
foo = await anext(bar_iter) # anext doesn't exist, but see below
except StopIteration:
break
...
在上面的示例中,aiter()
和anext()
是虚构的函数;这些是iter()
和next()
兄弟的功能完全等价物,但不是__iter__
和__next__
,而是使用__aiter__
和__anext__
。也就是说,异步挂钩存在相同的功能,但通过前缀a
区别于非异步变体。
await
关键字存在重要区别,因此对于每次迭代,async for
循环产生控制权,以便其他协同程序可以运行。
同样,为了重新迭代,所有这些都已经在Python 3.5中添加(参见PEP 492),Python 3.6中的所有新功能都是你可以在列表推导中使用这样的循环。在生成器表达式和set和dict理解中,就此而言。
最后但同样重要的是,同一组更改还可以在理解的表达式部分中使用await <expression>
,因此:
[await func(i) for i in someiterable]
现在可以。
答案 1 :(得分:11)
我认为我理解
aiter()
函数是异步调用的,因此aiter
的每次迭代都可以继续进行,而前一个函数不必返回(或者是这种理解)错?)。
这种理解是错误的。 async for
循环的迭代不能并行执行。 async for
与常规for
循环一样顺序。
async for
的异步部分是它允许迭代器await
代表协程迭代它。它仅适用于异步协程,仅用于特殊的异步迭代。除此之外,它主要就像常规for
循环一样。