从 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 而不是 break
ing 以获得预期的行为:
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())
我有一种情况想从异步 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 而不是 break
ing 以获得预期的行为:
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())