为何asyncio Task中的异常未被存储反而被立即抛出?
为什么你的asyncio.Task异常会被立即抛出?
嘿,这个问题其实是对await行为和asyncio.Task异常处理机制的常见误解~
你以为await task之后还能调用task.exception()获取异常,但实际上当你await一个Task时,一旦Task内部抛出异常,await会直接把这个异常重新抛出,就像你直接调用了那个抛出异常的协程一样。这是await的设计逻辑:它会帮你把Task的执行结果(或者异常)直接传递出来,而不是让Task把异常存着等你手动取。
那task.exception()什么时候有用呢?当你没有通过await来等待Task完成的时候——比如你用loop.create_task()创建了任务但没await,而是通过其他方式(比如add_done_callback回调,或者检查task.done()状态)来确认任务完成,这时候Task会把异常存储起来,你就可以用task.exception()获取它,而不会被自动抛出。
举两个例子对比一下:
例子1:用await时,需要捕获异常
import asyncio async def bad_task(): raise Exception("Oops, something went wrong!") async def test(): loop = asyncio.get_event_loop() task = loop.create_task(bad_task()) try: await task except Exception as e: print(f"捕获到异常:{e}") # 任务完成后,依然可以调用exception()获取异常 exp = task.exception() print(f"通过task.exception()获取的异常:{exp}") asyncio.run(test())
例子2:不await,用回调获取异常
import asyncio async def bad_task(): raise Exception("Oops, something went wrong!") def handle_done(task): exp = task.exception() if exp: print(f"回调里获取到异常:{exp}") async def test(): loop = asyncio.get_event_loop() task = loop.create_task(bad_task()) task.add_done_callback(handle_done) # 这里不用await,通过短暂等待让任务完成 await asyncio.sleep(0.1) asyncio.run(test())
总结一下关键点:
- 当你
awaitTask时,异常会被await主动重新抛出,所以必须用try/except捕获,没法直接走到task.exception()那一步 - 当你不通过
await等待Task完成时,异常会被Task内部存储,这时候才能通过task.exception()安全获取
内容的提问来源于stack exchange,提问作者Daniel Drexler
相关产品推荐
相关产品推荐

