脱离 Python 异步

tzi*_*nge 3 python python-asyncio

我遇到了一种情况,我想打破异步 for 循环。我设法将问题减少到下面的应用程序。我希望在退出 main 中的循环时进入上下文管理器的“最后”部分。换句话说,预期的结果是

尝试

第456章

最后

完毕

但我得到的是

尝试

第456章

完毕

最后

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

这是代码

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())
Run Code Online (Sandbox Code Playgroud)

我发现这个错误报告看起来很相似,但据我所知,它在 3.8 之前就已得到解决。我在 3.8.2 和 3.9.6 上测试了我的问题

thi*_*ord 6

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

如果您确定不再需要生成器,您可以关闭 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())

Run Code Online (Sandbox Code Playgroud)