如何解决外部异步上下文管理器在内部异步生成器之前完成
给出以下最小示例:
@asynccontextmanager
async def async_context():
try:
yield
finally:
await asyncio.sleep(1)
print('finalize context')
async def async_gen():
try:
yield
finally:
await asyncio.sleep(2)
# will never be called if timeout is larger than in async_context
print('finalize gen')
async def main():
async with async_context():
async for _ in async_gen():
break
if __name__ == "__main__":
asyncio.run(main())
我正在 break
迭代异步生成器,我希望 finally 块在我的异步上下文管理器 finally
块运行之前完成。在这个例子中,"finalize gen"
永远不会被打印,因为程序在这之前就退出了。
请注意,我特意在生成器 2
块中选择了 finally
超时,以便上下文管理器 finally
有机会在此之前运行。如果我为两个超时选择 1
,则将打印两条消息。
这是一种竞争条件吗?我希望在程序完成之前完成所有 finally
块。
如何防止上下文管理器 finally
块在生成器 finally
块完成之前运行?
上下文:
我使用 playwright 来控制 Chrome 浏览器。外部上下文管理器提供一个页面,它在 finally
块中关闭。
我正在使用 python 3.9.0
。
试试这个例子:https://repl.it/@trixn86/AsyncGeneratorRaceCondition
解决方法
异步上下文管理器对异步生成器一无所知。实际上,main
中的任何内容都不知道您 break
之后的异步生成器。你没有办法等待生成器的最终确定。
如果要等待生成器关闭,则需要显式处理关闭:
async def main():
async with async_context():
gen = async_gen()
try:
async for _ in gen:
break
finally:
await gen.aclose()
在 Python 3.10 中,您将能够使用 contextlib.aclosing
代替 try/finally:
async def main():
async with async_context():
gen = async_gen()
async with contextlib.aclosing(gen):
async for _ in gen:
break
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。