当没有引用时,在其finally块中没有“等待”的异步发电机会立即关闭吗? set_asyncgen_hooks 环境

问题描述

根据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)

打印相同的内容,看起来asynciotrio都对我的问题说“否”,因为如果异步发电机如我所愿立即关闭,它们将打印{{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

根据PEP5250 1 2 3 finalized end of main() 进行了一些骇人听闻的工作,称为asynciosys.set_asyncgen_hooks()也会这样做。我相信这就是异步发电机无法按我期望的那样工作的原因。这是可以理解的,因为对于finally块包含trio的异步生成器来说是必需的。

更精确的问题

所以我的问题是:

如果您使用的是cpython,并且您使用的异步库没有执行上述操作,那么在finally块中没有await的异步生成器将在没有参考吗?

环境

  • cpython 3.8.1
  • 三重奏0.17.0

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)