【问题标题】:Python Asynchronous Comprehensions - how do they work?Python 异步理解——它们是如何工作的?
【发布时间】:2017-07-09 05:05:53
【问题描述】:

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

【问题讨论】:

  • 我也对异步生成器很好奇。行为相同还是不同?

标签: python asynchronous list-comprehension python-3.6


【解决方案1】:

认为我知道aiter() 函数是异步调用的,因此aiter 的每次迭代都可以继续进行,而前一个迭代不一定会返回(或者这种理解是否错误?)。

这种理解是错误的。 async for 循环的迭代不能并行执行。 async for 与常规 for 循环一样连续。

async for 的异步部分是它让迭代器await 代表协程对其进行迭代。它仅用于异步协程中,并且仅用于特殊的异步迭代。除此之外,它几乎就像一个常规的for 循环。

【讨论】:

  • 谢谢,看来我需要先正确理解协程,然后再尝试使用 async。我很感激更正。 :)
【解决方案2】:

您基本上是在问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() 兄弟,但它们使用__aiter____anext__ 而不是__iter____next__。也就是说,异步钩子存在相同的功能,但通过前缀a 与它们的非异步变体区分开来。

await 关键字有关键区别,因此对于每次迭代,async for 循环产生控制权,以便其他协程可以运行。

再次重申,所有这些都已在 Python 3.5 中添加(请参阅PEP 492),Python 3.6 中的所有新功能是您也可以在列表推导中使用这样的循环。在生成器表达式以及集合和字典推导中,就此而言。

最后但并非最不重要的一点是,同样的一组更改也使得在理解的表达式部分使用await <expression> 成为可能,因此:

[await func(i) for i in someiterable]

现在可以了。

【讨论】:

  • 感谢 Martijn 的详细回答。所以async for 循环的行为与普通的for 循环相同,除了循环迭代的控制传递给封闭的协程?我将不得不正确地审查协程的使用,但这更有意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 2016-01-16
  • 1970-01-01
  • 2018-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多