Python 异步任务取消与异常处理
发布时间 - 2026-01-28 00:00:00 点击率:次asyncio.cancel() 不能强制终止协程,仅设取消标记并在下次 await 时抛 CancelledError;需协程主动配合(如插入 await、检查 cancelled())才能真正响应取消。
asyncio.cancel() 能否真正终止正在运行的协程
asyncio.cancel() 并不会强制中断协程执行,它只是给 Task 设置一个取消标记,并在下一次 await 时抛出 CancelledError。如果协程里全是 CPU 密集型计算、没任何 await,那取消就完全不生效。
常见错误现象:调用 task.cancel() 后,任务仍在后台跑满 CPU,日志里也看不到异常。
- 必须确保协程中存在可取消的挂起点,比如
await asyncio.sleep(1)、await aiohttp.get(...)、await queue.get() - 长时间计算逻辑要主动插入
await asyncio.sleep(0)或await asyncio.shield(...)(慎用)来让出控制权 - 捕获
CancelledError后,通常应直接返回或清理资源,不要“吞掉”后继续执行
如何安全地在 cancel 后释放资源(如文件句柄、连接)
协程被取消时,CancelledError 是继承自 BaseException 的,所以普通 except Exception: 捕获不到,必须显式处理。
使用场景:异步写文件、维持 WebSocket 连接、持有数据库连接池租约等。
- 用
try/except CancelledError:包裹关键清理逻辑,或更推荐用async with+ 支持异步__aexit__的上下文管理器 - 避免在
finally块里做耗时 await 操作(如await db.close()),因为此时事件循环可能已关闭;可改用loop.create_task()延迟调度 - 若清理本身也可能被取消(比如
await redis.connection_pool.disconnect()超时),需加超时控制:await asyncio.wait_for(cleanup(), timeout=2.0)
asyncio.gather() 中部分任务被取消时的异常传播行为
asyncio.gather() 默认遇到任意子任务异常(包括 CancelledError)就立即停止并抛出,但具体抛什么,取决于 return_exceptions 参数。
参数差异:
-
return_exceptions=False(默认):只要有一个任务被取消,整个gather就 raiseCancelledError,其余任务状态不确定(可能还在跑) -
return_exceptions=True:被取消的任务返回CancelledError实例而非抛出,其他任务继续运行,最终结果是混合列表 - 注意:即使设了
return_exceptions=True,主协程仍可能因父级取消而中断,不能依赖它“保底执行完”
示例: results = await asyncio.gather(task_a, task_b, return_exceptions=True) —— 若 task_a 被取消,results[0] 是 CancelledError 实例,results[1 是 
task_b 的返回值。
取消信号从上层传入深层协程的常用模式
深层协程(比如嵌套三层 await)无法自动感知外层 Task 是否被取消,必须显式传递取消上下文或检查 asyncio.current_task().cancelled()。
容易踩的坑:写了个工具函数 fetch_with_retry(),内部重试逻辑没检查取消状态,导致即使外层已 cancel,它还在傻等重试间隔。
- 推荐方式:把
asyncio.Task或asyncio.CancelScope(来自 anyio)作为参数传入,或使用asyncio.shield()显式保护不可取消段 - 轻量检查:在循环或重试开头加
if asyncio.current_task().cancelled(): raise asyncio.CancelledError() - 避免用
time.sleep()或while True:死循环,它们不响应取消;改用await asyncio.sleep()并配合取消检查
复杂点在于,取消不是“硬杀”,而是协作式中断 —— 每一层都要愿意停下来,否则信号就断在半路了。
# python
# redis
# websocket
# 工具
# ai
# 异步任务
# red
# if
# while
# try
# 循环
# 继承
# raise
# finally
# 事件
# 异步
# 数据库
# 抛出
# 还在
# 重试
# 并在
# 都要
# 句柄
# 长时间
# 下一
# 写了
# 管理器
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程
Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)
公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?
如何快速重置建站主机并恢复默认配置?
Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性
php结合redis实现高并发下的抢购、秒杀功能的实例
进行网站优化必须要坚持的四大原则
Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】
Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理
Laravel API资源类怎么用_Laravel API Resource数据转换
Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】
韩国服务器如何优化跨境访问实现高效连接?
网站建设整体流程解析,建站其实很容易!
深入理解Android中的xmlns:tools属性
如何在IIS中新建站点并解决端口绑定冲突?
Laravel怎么做缓存_Laravel Cache系统提升应用速度的策略与技巧
html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】
如何基于云服务器快速搭建个人网站?
香港服务器网站生成指南:免费资源整合与高速稳定配置方案
php在windows下怎么调试_phpwindows环境调试操作说明【操作】
如何在橙子建站上传落地页?操作指南详解
小米17系列还有一款新机?主打6.9英寸大直屏和旗舰级影像
Android okhttputils现在进度显示实例代码
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
JavaScript Ajax实现异步通信
Laravel如何优雅地处理服务层_在Laravel中使用Service层和Repository层
如何在宝塔面板中修改默认建站目录?
Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验
如何基于PHP生成高效IDC网络公司建站源码?
jQuery validate插件功能与用法详解
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
详解Huffman编码算法之Java实现
手机网站制作与建设方案,手机网站如何建设?
武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?
Python高阶函数应用_函数作为参数说明【指导】
百度浏览器如何管理插件 百度浏览器插件管理方法
如何在HTML表单中获取用户输入并用JavaScript动态控制复利计算循环
邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?
如何有效防御Web建站篡改攻击?
简单实现jsp分页
lovemo网页版地址 lovemo官网手机登录
javascript中对象的定义、使用以及对象和原型链操作小结
深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?
如何为不同团队 ID 动态生成多个非值班状态按钮
如何正确下载安装西数主机建站助手?
东莞专业网站制作公司有哪些,东莞招聘网站哪个好?
黑客入侵网站服务器的常见手法有哪些?
如何在阿里云虚拟主机上快速搭建个人网站?
如何挑选高效建站主机与优质域名?
Python自动化办公教程_ExcelWordPDF批量处理案例

