为什么会立即从asyncio任务中引发此异常?

时间:2018-04-26 22:55:42

标签: python-3.x python-asyncio

我从文档中了解到asyncio.Tasks作为asyncio.Future子类,将存储在其中引发的异常,并且可以在我闲暇时检索它们。

但是,在此示例代码中,会立即引发异常:

import asyncio

async def bad_task():
    raise Exception()

async def test():
    loop = asyncio.get_event_loop()
    task = loop.create_task(bad_task())
    await task

    # I would expect to get here
    exp = task.exception()
    # but we never do because the function exits on line 3

loop = asyncio.get_event_loop()
loop.run_until_complete(test())
loop.close()

示例输出(Python 3.6.5):

python3 ./test.py
Traceback (most recent call last):
  File "./test.py", line 15, in <module>
    loop.run_until_complete(test())
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/base_events.py", line 468, in run_until_complete
    return future.result()
  File "./test.py", line 9, in test
    await task
  File "./test.py", line 4, in bad_task
    raise Exception()
Exception

这是创造和创造的怪癖吗?已经在异步代码中调用任务?

2 个答案:

答案 0 :(得分:5)

await将引发任务抛出的任何异常,因为它意味着使异步代码看起来几乎与同步代码完全相同。如果要捕获它们,可以使用普通的try...except子句。

答案 1 :(得分:2)

Matti解释说,协程引发的例外情况会传播到等待网站。这是故意的,因为它确保默认情况下不会以无提示方式传递错误。但是,如果需要这样做,那么在没有立即访问其结果/异常的情况下等待任务完成肯定是可能

通过使用小型中间Future

,这是一种简单有效的方法
async def test():
    loop = asyncio.get_event_loop()
    task = loop.create_task(bad_task())
    task_done = loop.create_future()  # you could also use asyncio.Event
    # Arrange for task_done to complete once task completes.
    task.add_done_callback(task_done.set_result)

    # Wait for the task to complete. Since we're not obtaining its
    # result, this won't raise no matter what bad_task() does...
    await task_done
    # ...and this will work as expected.
    exp = task.exception()