为何代码中出现asyncio.exceptions.InvalidStateError: Exception is not set.错误?
问题解析:asyncio.exceptions.InvalidStateError: Exception is not set.
错误含义(当前场景下)
这个错误直接说明:你调用task.exception()时,目标任务既没有因抛出异常终止,也未处于已完成状态。
放到你的代码场景里:asyncio.wait(tasks, timeout=2)只是让主线程停止等待任务完成,不会主动取消或终止未完成的任务。当超时触发时,task2的asyncio.sleep(3)还没执行完毕,它仍处于**pending(运行中)**状态——此时任务既没抛出异常,也没结束,自然没有异常可以获取,调用task.exception()就会触发这个非法状态错误。
代码问题分析
你的get_results_or_none函数只判断了任务是否被取消,完全忽略了任务可能还在运行的情况:
task1在超时前就完成了(sleep(1)< 2秒),所以可以正常调用result()/exception()task2超时后仍在运行,状态为pending,此时调用task.exception()违反了API的调用规则,直接报错
修复方案
方案1:主动取消未完成的任务
在asyncio.wait返回后,取消所有未完成的任务,让它们进入已取消状态,再处理:
async def main(): tasks = [ asyncio.create_task(asyncio.sleep(1), name='task1'), asyncio.create_task(asyncio.sleep(3), name='task2'), ] # 接收done和pending两个返回值,区分已完成和未完成任务 done, pending = await asyncio.wait(tasks, timeout=2) # 取消所有未完成的任务 for task in pending: task.cancel() return get_results_or_none(tasks)
此时task2会被标记为已取消,task.cancelled()返回True,进入对应的处理分支,不会触发错误。
方案2:先判断任务是否已完成再处理
修改get_results_or_none函数,先检查任务是否处于done状态,再进行后续操作:
def get_results_or_none(tasks): results = [] for task in tasks: if task.cancelled(): print(task.get_name(), 'cancelled') results.append(None) elif task.done(): # 任务已完成,再判断是正常结束还是抛出异常 exc = task.exception() if exc: print(task.get_name(), exc) results.append(None) else: res = task.result() print(task.get_name(), 'result', res) results.append(res) else: # 任务仍在运行,按需处理 print(task.get_name(), 'still running') results.append(None) return results
这样就能避免在任务pending状态下调用exception()或result(),从根源上避免错误。
补充:asyncio Task的关键状态
asyncio Task有三种核心状态:
- Pending:任务正在执行,未完成
- Done:任务已终止,包含三种子情况:
- 正常结束:
task.result()返回任务返回值,task.exception()返回None - 抛出异常:
task.exception()返回对应的异常对象 - 被取消:
task.cancelled()返回True,调用task.result()会抛出CancelledError
- 正常结束:
只有当任务处于Done状态且因异常终止时,task.exception()才会返回有效异常;其他状态下调用都会触发InvalidStateError。
内容的提问来源于stack exchange,提问作者user3225309
相关产品推荐
相关产品推荐

