为什么这个异常会立即从 asyncio 任务中引发?
Why is this exception immediately raised from an asyncio Task?
我对文档的理解是 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
这是在异步代码中创建和调用任务的怪癖吗?
await
将引发任务抛出的任何异常,因为它旨在使异步代码看起来几乎与同步代码完全一样。如果你想抓住它们,你可以使用普通的 try...except
子句。
正如 Matti 所解释的,协程引发的异常会传播到等待站点。这是有意为之的,因为它确保错误不会在默认情况下静默传递。但是,如果需要这样做,肯定 可以 等待任务完成而不立即访问其 result/exception。
这是一个简单而有效的方法,通过使用一个小的中间体 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()
我对文档的理解是 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
这是在异步代码中创建和调用任务的怪癖吗?
await
将引发任务抛出的任何异常,因为它旨在使异步代码看起来几乎与同步代码完全一样。如果你想抓住它们,你可以使用普通的 try...except
子句。
正如 Matti 所解释的,协程引发的异常会传播到等待站点。这是有意为之的,因为它确保错误不会在默认情况下静默传递。但是,如果需要这样做,肯定 可以 等待任务完成而不立即访问其 result/exception。
这是一个简单而有效的方法,通过使用一个小的中间体 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()