2017-02-20 50 views
25

我无法理解Python 3.6中引入的异步引入的使用。作为一个免责声明,我没有很多处理Python中异步代码的经验。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

我很好奇异步生成器。相同或不同的行为? –

回答

16

你基本上是问一个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)呼叫不是异步的;它阻止。

现在提供async for替换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] 

现在是可能的。

+0

感谢Martijn的详细解答。所以'async for'循环的行为与普通的'for'循环相同,除了循环迭代的控制被传递给封装的协程?我将不得不恰当地检查协程的使用,但这更有意义。 –

10

据我所知,aiter()函数被异步调用,使aiter每次迭代可以在没有前一个必然回归尚未进行(或这是理解错了吗?)。

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

async for的异步部分是它让代表协程的迭代器await迭代它。它仅用于异步协程中,并且仅用于特殊的异步可执行文件。除此之外,它几乎就像一个普通的for循环。

+0

谢谢,看来我需要去正确地理解协程,然后才会围绕使用'async'来包装头部。我赞赏这一更正。 :) –