从 Python 异步中断

Break from Python async for

我有一种情况想从异步 for 循环中中断。我设法将问题减少到下面的应用程序。我希望在从 main 中的循环中断时进入上下文管理器的 'finally' 部分。也就是说,预期的结果是

try

456

finally

done

但我得到的是

try

456

done

finally

然后在应用程序关闭时出现异常。

这是代码

import asyncio
from contextlib import asynccontextmanager

@asynccontextmanager
async def receiving():
    try:
        print('try')
        yield 123
    finally:
        print('finally')

async def request_all():
    async with receiving():
        yield 456

async def main():
    async for r in request_all():
        print(r)
        break
    print('done')

asyncio.run(main())

我发现 this 似乎类似的错误报告,但据我所知,它已在 3.8 之前解决。我在 3.8.2 和 3.9.6

上测试了我的问题

我可以看出这种行为是多么令人困惑,但我不认为这是一个错误。如果使用 break 绕过异步迭代器的耗尽,则永远不会将 async with 留在 request_all 中,因此 finally 块在事件循环完成之前不会执行.这样做的好处是您可以可以稍后耗尽发电机。

如果您确定不再需要生成器,您可以关闭 async_generator 而不是 breaking 以获得预期的行为:

import asyncio
from contextlib import asynccontextmanager

@asynccontextmanager
async def receiving():
    try:
        print('try')
        yield 123
    finally:
        print('finally')

async def request_all():
    async with receiving():
        yield 456

async def main():
    gen = request_all()
    async for r in gen:
        print(r)
        await gen.aclose() #instead of break
    print('done')

asyncio.run(main())