首页 > 解决方案 > 如何确保使用 asyncio.gather 执行所有任务?

问题描述

使用asyncio.gather时,当其中一个任务引发异常时,所有任务都不会执行:

# coding: utf-8
import asyncio


async def foo(i):
    await asyncio.sleep(0.1)
    if i == 2:
        print("2: 1/0")
        1/0
    print(i)


async def main():
    futures = []
    for i in range(1000):
        futures.append(foo(i))
    await asyncio.gather(*futures)


asyncio.run(main())
0
1
2: 1/0
3
4
5
6
7
[...]
501
502
503
504
Traceback (most recent call last):
  File "<input>", line 24, in <module>
  File "/usr/lib/python3.8/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "<input>", line 21, in main
  File "<input>", line 9, in foo
ZeroDivisionError: division by zero

如何确保在退出之前执行所有任务asyncio.gather?我知道这不是默认行为,asyncio.gather因为如果我的一项任务从未完成,则永远不会引发异常。我的问题更多:我如何执行一组任务收集并等待所有完成/提升,然后再继续?

标签: pythonpython-asyncio

解决方案


我认为您想密切关注asyncio.gather 的文档

如果 return_exceptions 为 False(默认值),则第一个引发的异常会立即传播到在 gather() 上等待的任务。aws 序列中的其他等待对象不会被取消,并将继续运行。

如果 return_exceptions 为 True,则将异常视为成功结果,并在结果列表中聚合。

根据我的阅读,看起来如果您要这样打电话asyncio.gather...

await asyncio.gather(*futures, return_exceptions=True)

...你应该得到你想要的行为。


推荐阅读