Python aiohttp异步请求出现Task异常未检索及AttributeError: __aexit__报错
报错核心原因拆解
你的判断没错,这段代码不存在语法层面的错误,所有报错都属于运行时的API调用规则偏差,具体分为三部分:
- 触发
AttributeError: __aexit__的根本问题:aiohttp.ClientSession的调用方式错误。你在代码中直接把aiohttp.ClientSession类本身作为异步上下文管理器使用,没有通过加括号的方式创建类实例。Python的异步上下文协议要求,解释器会从上下文对象的类型上查找对应的__aenter__、__aexit__方法:当你传入的是aiohttp.ClientSession类对象时,这个对象的类型是Python内置的type元类,元类本身没有实现异步上下文接口,因此解释器在查找__aexit__方法时找不到对应属性,直接抛出报错。而加括号创建实例后,实例的类型就是aiohttp.ClientSession,这个类实现了对应的异步上下文方法,协议校验才会通过。 - "Task exception was never retrieved"属于连锁告警,不是独立故障:当协程内部因为上面的属性错误崩溃后,
asyncio.wait仅会等待所有任务执行完成,不会主动检索任务内部抛出的异常,因此asyncio框架会在任务垃圾回收时打出告警,提示该任务的异常没有被获取处理。只要修复了协程内部的报错源头,这个告警会自动消失。 - 代码中还有一处不符合aiohttp使用规范的隐性问题:你写的
async with await session.get(url) as response:写法存在逻辑偏差。session.get()方法本身返回实现了异步上下文接口的请求管理器,会在进入上下文阶段自动发起HTTP请求、在退出阶段自动释放连接资源;如果额外在前面加await,会提前触发请求逻辑,跳过上下文管理器的初始化流程,就算第一处错误修复了,也会出现连接资源泄漏的问题。
具体修复方案
- 修正
ClientSession的实例化逻辑,补上实例化需要的括号:async with aiohttp.ClientSession() as session - 修正请求上下文的写法,去掉
session.get前多余的await:async with session.get(url) as response - 修复后的
get_page函数参考代码:
async def get_page(url): async with aiohttp.ClientSession() as session: async with session.get(url) as response: page_text = await response.text() print(page_text)
关于是否需要添加try-catch的说明
对于这类因为API使用错误导致的确定性故障,不建议优先加try-catch捕获块。当前的报错属于代码编写时的逻辑偏差,不属于网络波动、接口超时这类运行时不可预知的异常场景,通过修正API调用方式就能从根源解决问题。过早添加全局try-catch反而会掩盖这类基础错误,提升后续排障的成本。
修复完成后,配合你开启了多线程模式的Flask服务,3个每个阻塞2秒的接口的总请求耗时会稳定在2秒左右,符合异步并发的预期效果。
内容的提问来源于stack exchange,提问作者PeterWu
相关产品推荐
相关产品推荐

