python - 异步收集异常处理程序不起作用
问题描述
我正在尝试将 exception_handler 与 asyncio.gather 一起使用
我的代码:
import asyncio
def exception_handler(loop, context):
print('Exception handler called')
async def coro():
print("coro")
raise RuntimeError("BOOM!")
return 1
def main():
loop = asyncio.get_event_loop()
loop.set_exception_handler(exception_handler)
group = asyncio.gather(coro(), coro(), coro())
results = loop.run_until_complete(group)
print(results)
main()
当我运行它时,我得到的不是“调用异常处理程序”,而是:
Traceback (most recent call last):
File "test.py", line 23, in <module>
main()
File "test.py", line 20, in main
results = loop.run_until_complete(group)
File "/usr/lib64/python3.7/asyncio/base_events.py", line 583, in run_until_complete
return future.result()
File "test.py", line 12, in coro
raise RuntimeError("BOOM!")
解决方案
似乎 Python 文档不清楚asyncio
异常处理程序实际上应该处理什么。
引用此错误报告中的 Python 核心开发人员 Andrew Svetlov 的话:
asyncio 异常处理程序应该只捕获未处理的异常,而不是所有引发的异常。
[...] 衍生任务的异常不会隐式传播到父任务。这就是为什么未处理异常并将其传递给已注册的异常处理程序的原因。
该报告给出了以下示例:
async def test():
raise Exception("Something goes wrong")
async def main():
#Un-comment either 1 of the following 3 lines
# await test() # will not call exception_handler
# await asyncio.gather(test()) # will not call exception_handler
# asyncio.create_task(test()) # will call exception_handler
await asyncio.sleep(5)
在您的情况下,您可以处理任何同步代码中的异常:
import asyncio
async def coro():
print("coro")
raise RuntimeError("BOOM!")
return 1
def main():
loop = asyncio.get_event_loop()
group = asyncio.gather(coro(), coro(), coro())
try:
results = loop.run_until_complete(group)
except RuntimeError:
# handle exception
print(results)
main()
推荐阅读
- python - Tensorflow NMT with Attention 教程——需要帮助理解损失函数
- java - 如何查询具有未定义深度的分层类别树实体
- ruby-on-rails - Heroku create 给出“Permission denied @ rb_sysopen”
- ios - 如何在外部模块中覆盖 public init(frame:) ?
- mysql - 如何比较两列以及如何获取所有行?
- node.js - 使用 chrome 的调试器如何无法在 VSCode 中绑定断点?
- javascript - 在 Web 浏览器中导入 ES6 模块不起作用
- javascript - 如何使用 JavaScript 获取客户的国家地址 IP 地址?
- android - 如何解决 Gradle 项目同步失败。基本功能(例如编辑、调试)将无法正常工作
- javascript - 搜索包含特定字符串的所有标签,然后将其更改为声明值