逻辑异常由业务代码主动抛出,运行环境异常由asyncio运行时机制引发;前者源于协程内部逻辑错误,后者反映资源、调度或上下文问题,需分别采用防御性校验与结构化响应策略。

async 函数中的逻辑异常和运行环境异常,本质区别在于**谁触发、何时暴露、是否可预测**。它们不是按“同步/异步”划分的两类错误,而是按**错误来源与传播时机**区分的两类问题。
逻辑异常:由业务代码主动抛出或计算路径导致
这类异常源于开发者编写的协程内部逻辑,比如参数校验失败、状态不合法、业务规则被违反等。它在协程执行到对应语句时立即发生,但是否立刻中断流程,取决于是否被 await 触发和是否被 try-except 捕获。
- 典型例子:
if user_id < 0: raise ValueError("user_id must be positive") - 协程中直接
raise的异常,只要没被本地try-except吞掉,就会在await该协程时向上抛出 - 即使协程已创建为 task,只要未 await 或未调用
task.result(),异常就只停留在 task 对象里,不会影响主流程
运行环境异常:由 asyncio 运行时机制引发
这类异常不是你写的 raise,而是事件循环、调度器或底层系统在管理协程生命周期时产生的信号。它们往往反映资源、调度或上下文层面的问题,具有强环境依赖性。
- 典型例子:
asyncio.CancelledError(任务被取消)、TimeoutError(wait_for超时)、RuntimeError(如在非 running 的 event loop 中调用create_task) - 它们通常不能靠“检查输入”提前规避,而需通过结构化控制流(如
try/except CancelledError+ 清理逻辑)来响应 -
CancelledError是唯一一个被设计为“可被捕获但建议 re-raise”的异常,因为取消是协作式中断,不 re-raise 可能导致资源泄漏
关键差异总结
逻辑异常是你代码里的“错”,运行环境异常是 asyncio 系统发出的“通知”。前者强调校验与防御,后者强调响应与收尾。混用处理方式容易出问题:比如用 if 判断去防 CancelledError,或把 TimeoutError 当作业务错误返回给用户。


















