asyncio.gather的文档中说
如果return_exceptions为False
(默认值),第一个引发的异常会立即传播到gather()
上等待的任务,aws序列中的其他等待项不会被取消,而是继续运行。
然而,从一个简单的测试来看,如果其中一个任务在return_exceptions为False
时引发异常,则所有其他可等待的任务都将被取消(或者更准确地说,如果术语对我来说不清楚,则其他可等待的任务不会完成它们的工作):
import asyncio
async def factorial(name, number, raise_exception=False):
# If raise_exception is True, will raise an exception when
# the loop counter > 3
f = 1
for i in range(2, number + 1):
print(f' Task {name}: Compute factorial({i})...')
if raise_exception and i > 3:
print(f' Task {name}: raising Exception')
raise Exception(f'Bad Task {name}')
await asyncio.sleep(1)
f *= i
print(f'==>> Task {name} DONE: factorial({number}) = {f}')
return f
async def main():
tasks = [factorial('A', 5), # this will not be finished
factorial('B', 10, raise_exception=True),
factorial('C', 2)]
try:
results = await asyncio.gather(*tasks)
print('Results:', results)
except Exception as e:
print('Got an exception:', e)
asyncio.run(main())
这段代码所做的事情,为了简单起见,它定义了3个任务,并对它们调用asyncio.gather()
,其中一个任务在其他任务完成之前引发了异常,而另一个任务还没有完成。
实际上,我甚至无法理解文档中所说的内容--如果gather
上等待的任务引发并捕获了异常,我甚至无法获得返回的结果(即使其他任务以某种方式完成了)。
我是否遗漏了什么,或者文档有问题?
这是用Python 3.7.2测试过的。
2条答案
按热度按时间ars1skjm1#
我已经运行了您的代码,并得到了以下输出,正如文档中所预期的那样。
∮发生了什么事
1.任务A、B和C被提交到队列;
1.所有任务都在运行,而C最早完成。
1.任务B引发异常。
await asyncio.gater()
立即返回,print('Got an exception:', e)
返回屏幕。1.任务A继续运行并打印“==〉〉任务A完成...”
∮你的测试有什么问题
如@deceze所述,程序在捕获异常并返回
main()
后立即退出,因此任务A和C终止是因为整个进程终止,而不是因为取消。要修复此问题,请将
await asyncio.sleep(20)
添加到main()
函数的末尾。o4hqfura2#
这里主要问题的答案是使用asyncio.as_complete。将
main()
函数代码更改为: