如何在Python中使用`async for`? [英] How to use `async for` in Python?

查看:689
本文介绍了如何在Python中使用`async for`?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的意思是我从使用async for中学到什么.这是我用async for编写的代码,AIter(10)可以替换为get_range().

I mean what do I get from using async for. Here is the code I write with async for, AIter(10) could be replaced with get_range().

但是代码的运行方式类似于同步而不是异步.

But the code runs like sync not async.

import asyncio

async def get_range():
    for i in range(10):
        print(f"start {i}")
        await asyncio.sleep(1)
        print(f"end {i}")
        yield i

class AIter:
    def __init__(self, N):
        self.i = 0
        self.N = N

    def __aiter__(self):
        return self

    async def __anext__(self):
        i = self.i
        print(f"start {i}")
        await asyncio.sleep(1)
        print(f"end {i}")
        if i >= self.N:
            raise StopAsyncIteration
        self.i += 1
        return i

async def main():
    async for p in AIter(10):
        print(f"finally {p}")

if __name__ == "__main__":
    asyncio.run(main())

我排除的结果应该是:

start 1
start 2
start 3
...
end 1
end 2
...
finally 1
finally 2
...

但是,实际结果是:

start 0
end 0
finally 0
start 1
end 1
finally 1
start 2
end 2

我知道我可以通过使用asyncio.gatherasyncio.wait来获得例外结果.

I know I could get the excepted result by using asyncio.gather or asyncio.wait.

但是我很难理解使用async for而不是简单的for会得到什么.

But it is hard for me to understand what I got by use async for here instead of simple for.

如果我要遍历几个Feature对象并在一个对象完成后立即使用它们,什么是使用async for的正确方法.例如:

What is the right way to use async for if I want to loop over several Feature object and use them as soon as one is finished. For example:

async for f in feature_objects:
    data = await f
    with open("file", "w") as fi:
        fi.write()

推荐答案

但是我很难理解使用async for而不是简单的for会得到什么.

But it is hard for me to understand what I got by use async for here instead of simple for.

潜在的误解是期望 async for 自动并行化迭代.它不会这样做,它只是允许在异步源上进行顺序迭代 .例如,您可以使用async for遍历来自TCP流的行,来自Websocket的消息或来自异步DB驱动程序的数据库记录.

The underlying misunderstanding is expecting async for to automatically parallelize the iteration. It doesn't do that, it simply allows sequential iteration over an async source. For example, you can use async for to iterate over lines coming from a TCP stream, messages from a websocket, or database records from an async DB driver.

您不能使用普通的for进行上述任何操作,至少不能阻止事件循环,因为for调用async for的原因. ..of"rel =" noreferrer>其他 语言与async/await和通用for.

You could do none of the above with an ordinary for, at least not without blocking the event loop, because for calls __next__ as a blocking function and doesn't await its result. You cannot compensate by manually awaiting each element because for expects __next__ to signal the end of iteration by raising an exception - and if __next__ is a coroutine, the exception won't be visible before awaiting it. This is why async for was introduced, not just in Python, but also in other languages with async/await and generalized for.

如果要并行运行迭代,则需要将它们作为并行协程启动,并使用

If you want to run the iterations in parallel, you need to start them as parallel coroutines and use asyncio.as_completed or equivalent to retrieve their results as they come:

async def x(i):
    print(f"start {i}")
    await asyncio.sleep(1)
    print(f"end {i}")
    return i

for f in asyncio.as_completed([x(i) for i in range(10)]):
    result = await f
    # ... do something with the result ...

这篇关于如何在Python中使用`async for`?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆