asyncio.gather 协程高级分组中的异常

Exceptions in high-level grouping of corountines with asyncio.gather

我目前正在做一个项目,我在其中启动了几个协同程序,我将它们与 asyncio.gather 组合在一起。然后,我将所有这些子组组合在一起,再次使用 asyncio.gather.
除非发生错误,否则一切正常。错误不会传播到主程序,而 return_exceptions 关键字未设置为 True。

重现方法如下:

import asyncio

async def ok_task():
    while True:
        await asyncio.sleep(0)

async def error_task():
    await asyncio.sleep(1)
    print("crashed!")
    raise RuntimeError

async def create_coros():
    return asyncio.gather(ok_task(), error_task())

def main():
    subgroup_1 = create_coros()
    subgroup_2 = create_coros()
    subgroup_3 = create_coros()

    main_group = asyncio.gather(subgroup_1, subgroup_2, subgroup_3)
    asyncio.get_event_loop().run_until_complete(
        main_group
    )
    asyncio.get_event_loop().run_forever()

if __name__ == "__main__":
    main()

crashed! 在控制台上正确出现了 3 次,但没有引发 RuntimeError

但是,如果我用 return await asyncio.gather(ok_task(), error_task()) 修改 create_coros 函数,则会出现异常行为。

谁能解释为什么没有额外的 await 就不会传播异常?

进行以下更改以使您的代码按预期工作。另一方面,如果我是你,我会尝试只使用一个 gather 并在那个 gather.

中累积所有协程
import asyncio


async def ok_task():
    """Not infinite loop  now"""
    n = 10
    while n:
        await asyncio.sleep(0.5)
        n -= 1
    return 100  # let's return some number


async def error_task():
    """It always make problems"""
    await asyncio.sleep(1)
    print("crashed!")
    raise RuntimeError("NOooo!!!")


async def create_coros():
    """Accumulate tasks here"""
    # return_exceptions=True - since we expect errors
    # should return some Coroutine which return result of 
    # await asyncio.gather(ok_task(), error_task(), return_exceptions=True)
    # await is used to return appropriate datatype for gather function
    # which expect coroutines as args
    return await asyncio.gather(ok_task(), error_task(), return_exceptions=True)


async def amain():
    # create several groups of coroutines
    subgroup_1 = create_coros()
    subgroup_2 = create_coros()
    subgroup_3 = create_coros()

    # gather expect coroutines 
    r = await asyncio.gather(subgroup_1, subgroup_2, subgroup_3)
    print(f"Final Result: {r}")


if __name__ == "__main__":
    asyncio.run(amain())