如何在Python中使用“async for”?

2024-05-16 05:38:26 发布

您现在位置:Python中文网/ 问答频道 /正文

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

但是代码的运行方式类似于sync而不是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())

我排除的结果应该是:

^{pr2}$

然而,真正的结果是:

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

我知道我可以通过使用asyncio.gatherasyncio.wait得到例外结果。在

但是我很难理解在这里用async for而不是简单的for得到了什么。在

如果我想在多个Feature对象上循环并在一个对象完成后立即使用它们,那么使用async for的正确方法是什么。例如:

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

Tags: 代码inselfasyncioforasyncmaindef
1条回答
网友
1楼 · 发布于 2024-05-16 05:38:26

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

潜在的误解是您似乎期望^{}自动地将迭代并行化。它不这样做,它只是允许在异步源上进行顺序迭代。例如,可以使用async for来迭代来自TCP流的行、来自websocket的消息或来自异步DB驱动程序的数据库记录。在

使用普通的for就不能执行上述任何操作,至少在不阻塞事件循环的情况下是这样,因为for^{}作为一个阻塞函数调用,而不等待其结果。您不能通过手动等待每个元素来进行补偿,因为for希望__next__通过引发异常来发出迭代结束的信号,并且如果__next__是一个协程,则在等待异常之前,异常将不可见。这就是为什么async for不仅在Python中被引入,而且在otherlanguages中也引入了async/await和{}。在

如果您想并行运行迭代,您需要将它们作为并行协程启动,并使用^{}或等效方法来检索它们的结果:

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 ...

相关问题 更多 >