外部异步上下文管理器在内部异步生成器之前完成
outer async context manager finalized before inner async generator
给定以下最小示例:
@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
ing 迭代异步生成器,我希望 finally 块在我的异步上下文管理器 finally
块 运行s 之前完成。在这个例子中 "finalize gen"
将永远不会被打印,因为程序在此之前退出。
请注意,我故意在生成器 finally
块中选择 2
的超时,以便上下文管理器 finally
有机会 运行 之前。如果我为两个超时都选择 1
,则将打印两条消息。
这是一种竞争条件吗?我希望所有 finally
个块在程序完成之前完成。
如何在生成器 finally
块完成之前阻止上下文管理器 finally
块到 运行?
对于上下文:
我用playwright来控制chromium浏览器。外部上下文管理器提供了一个在 finally
块中关闭的页面。
我正在使用 python 3.9.0
.
异步上下文管理器对异步生成器一无所知。事实上,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
给定以下最小示例:
@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
ing 迭代异步生成器,我希望 finally 块在我的异步上下文管理器 finally
块 运行s 之前完成。在这个例子中 "finalize gen"
将永远不会被打印,因为程序在此之前退出。
请注意,我故意在生成器 finally
块中选择 2
的超时,以便上下文管理器 finally
有机会 运行 之前。如果我为两个超时都选择 1
,则将打印两条消息。
这是一种竞争条件吗?我希望所有 finally
个块在程序完成之前完成。
如何在生成器 finally
块完成之前阻止上下文管理器 finally
块到 运行?
对于上下文:
我用playwright来控制chromium浏览器。外部上下文管理器提供了一个在 finally
块中关闭的页面。
我正在使用 python 3.9.0
.
异步上下文管理器对异步生成器一无所知。事实上,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