如何确保所有任务都使用 asyncio.gather 执行?
How to ensure all task are executed using 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
的默认行为,因为如果我的一项任务从未完成,则永远不会引发异常。我的问题更多:如何在继续之前执行收集任务池并等待所有 finished/raise?
我想你要密切关注 documentation for asyncio.gather:
If return_exceptions is False (default), the first raised exception
is immediately propagated to the task that awaits on gather(). Other
awaitables in the aws sequence won’t be cancelled and will continue
to run.
If return_exceptions is True, exceptions are treated the same as
successful results, and aggregated in the result list.
根据我的阅读,如果你像这样调用 asyncio.gather
...
await asyncio.gather(*futures, return_exceptions=True)
...你应该得到你想要的行为。
当使用 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
的默认行为,因为如果我的一项任务从未完成,则永远不会引发异常。我的问题更多:如何在继续之前执行收集任务池并等待所有 finished/raise?
我想你要密切关注 documentation for asyncio.gather:
If return_exceptions is False (default), the first raised exception is immediately propagated to the task that awaits on gather(). Other awaitables in the aws sequence won’t be cancelled and will continue to run.
If return_exceptions is True, exceptions are treated the same as successful results, and aggregated in the result list.
根据我的阅读,如果你像这样调用 asyncio.gather
...
await asyncio.gather(*futures, return_exceptions=True)
...你应该得到你想要的行为。