问题描述
根据this blog,如果没有引用,普通生成器将立即关闭。 (不过是cpython独有的)。我的问题是“这是否适用于在finally块中没有'await'的异步发电机?”
动机
我是异步库的作者,并且希望异步发电机像普通发电机一样工作。否则,用户必须编写类似这样的代码
agen = async_generator_function()
async with async_closing(agen):
async for v in agen:
if some_condition:
break
do_something()
代替此
async for v in async_generator_function():
if some_condition:
break
do_something()
这很烦人。幸运的是,它的unit test始终可以按我预期的那样工作,所以我想知道它是否得到保证。
调查
以下代码
import asyncio
async def agen_func():
try:
for i in range(10):
yield i
finally:
print('finalized')
async def main():
async for i in agen_func():
print(i)
if i > 2:
break
print('end of main()')
asyncio.run(main())
打印
0
1
2
3
end of main()
finalized
以及以下代码
import trio
async def agen_func():
try:
for i in range(10):
yield i
finally:
print('finalized')
async def main():
async for i in agen_func():
print(i)
if i > 2:
break
print('end of main()')
trio.run(main)
打印相同的内容,看起来asyncio
和trio
都对我的问题说“否”,因为如果异步发电机如我所愿立即关闭,它们将打印{{1} } finalized
之前。实际上,如果您使用这两个异步库,则我的问题的答案可能是“否”。
但这是一件有趣的事情。如果您不使用它们,异步发电机将按我的预期工作。
end of main()
async def agen_func():
try:
for i in range(10):
yield i
finally:
print('finalized')
async def main():
async for i in agen_func():
print(i)
if i > 2:
break
print('end of main()')
try:
main().send(None)
except stopiteration:
pass
这就是我当前正在开发的异步库的工作方式。
set_asyncgen_hooks
根据PEP525,0
1
2
3
finalized
end of main()
进行了一些骇人听闻的工作,称为asyncio
。 sys.set_asyncgen_hooks()
也会这样做。我相信这就是异步发电机无法按我期望的那样工作的原因。这是可以理解的,因为对于finally块包含trio
的异步生成器来说是必需的。
更精确的问题
所以我的问题是:
如果您使用的是cpython,并且您使用的异步库没有执行上述操作,那么在finally块中没有await
的异步生成器将在没有参考吗?
环境
- cpython 3.8.1
- 三重奏0.17.0
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)