Python异步理解 - 它们如何工作?

时间:2017-02-20 02:56:44

标签: python asynchronous list-comprehension python-3.6

我无法理解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这样的理解中的基本机制?

2 个答案:

答案 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循环一样。