Python Asyncio:在Gather()中处理异常-文档不清楚吗?

时间:2019-03-04 16:21:53

标签: python python-3.x

documentation for 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中进行了测试。

1 个答案:

答案 0 :(得分:1)

我已经运行了您的代码,并获得了文档所期望的以下输出。

  Task C: Compute factorial(2)...
  Task A: Compute factorial(2)...
  Task B: Compute factorial(2)...
==>> Task C DONE: factorial(2) = 2
  Task A: Compute factorial(3)...
  Task B: Compute factorial(3)...
  Task A: Compute factorial(4)...
  Task B: Compute factorial(4)...
  Task B: raising Exception
Got an exception: Bad Task B
  Task A: Compute factorial(5)...
==>> Task A DONE: factorial(5) = 120

发生了什么

  1. 任务A,B和C已提交到队列;
  2. 所有任务都在C最早完成时运行。
  3. 任务B引发异常。
  4. await asyncio.gater()立即返回,print('Got an exception:', e)返回屏幕。
  5. 任务A继续运行并打印“ == >>任务A完成...”

您的考试有什么问题

正如@deceze所说, 您的程序在捕获到异常后立即退出,并返回main()。因此,终止任务A和C的原因是整个过程死亡,而不是因为取消。

要解决此问题,请将await asyncio.sleep(20)添加到main()函数的末尾。