Python 3.11升级导致旧脚本崩溃或静默失效,主因是移除asyncio.coroutine、启用per-interpreter GIL、TaskGroup误用及asyncio.run()滥用;需升级库、弃用uvloop、确保TaskGroup在运行loop中、顶层单次调用asyncio.run()。

因为 Python 3.11 移除了 asyncio.coroutine,且默认启用 per-interpreter GIL,旧脚本若依赖已废弃的协程装饰器或未适配新事件循环行为,就会直接崩溃或静默失效。
asyncio.coroutine 被彻底移除导致 import 失败
Python 3.11 不再提供 asyncio.coroutine 装饰器——它早在 3.8 就被标记为 deprecated,3.11 直接删掉。很多旧版异步库(如 motor、某些自定义框架)仍保留类似这样的代码:
from asyncio import coroutine
运行时立刻报错:ImportError: cannot import name 'coroutine' from 'asyncio'
- 不是环境没装对,是代码本身调用了已不存在的符号
- 升级对应库(如
motor>=3.1.1)是最小改动解法 - 若无法升级,只能手动 patch 源码——但不推荐,维护成本高
uvloop 在双核机器上反而拖慢 QPS
很多旧脚本习惯性加 import uvloop; uvloop.install(),但在 Python 3.11 下,这会触发隐式性能退化:epoll_wait 阻塞超 50ms,P99 延迟翻三倍,QPS 倒退 42%。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 根本原因是 CPython 3.11 默认开启 per-interpreter GIL,与 uvloop 的 libuv 线程池回调不同步
- 临时缓解:设环境变量
PYTHONASYNCIODEBUG=0并绑定单核运行(taskset -c 0 python script.py) - 更稳方案:直接弃用 uvloop,用标准
asyncio.SelectorEventLoop,实测万级连接下更稳
TaskGroup 被误用在无 event loop 上下文中
旧脚本常把 asyncio.TaskGroup 放在同步 fixture、conftest 初始化、或非 async test 函数里,结果抛 RuntimeError: no running event loop。
- TaskGroup 必须运行在已启动的 event loop 内,不能“提前创建”
- pytest 中必须配合
pytest-asyncio插件 +asyncio_mode = "strict"才支持 async fixture - 若测试框架不支持 strict 模式,改用
asyncio.create_task+await asyncio.gather()更兼容
asyncio.run() 在循环中反复调用引发调度抖动
常见写法:for url in urls: asyncio.run(fetch(url)) —— 每次都重建事件循环,开销远超协程本身。
- CPython 3.11 虽优化了帧创建,但
asyncio.run()仍会重载 GIL 状态、重建调度器、初始化解释器 - 正确做法:只在顶层调一次
asyncio.run(main()),所有任务组织进main() - 需定时轮询?用
asyncio.get_event_loop().run_until_complete()复用已有 loop
真正卡住人的往往不是语法错误,而是旧脚本里那些“看起来正常”的调用,在 3.11 下悄悄改变了底层行为:GIL 同步方式变了、上下文传播逻辑变了、event loop 生命周期约束变严了。不跑起来看不出问题,一跑就崩得莫名其妙。

















