在 Python 3.10 中启用 uvloop 可使 asyncio Web 服务吞吐量提升 2–4 倍,但须在 asyncio.run() 前调用 uvloop.install() 或 set_event_loop_policy(),且在 uvicorn 启动 FastAPI 时需显式指定 --loop uvloop 或在 if name == "__main__": 中提前安装。

直接上结论:在 Python 3.10 中启用 uvloop 能让基于 asyncio 的 Web 服务(如 FastAPI、Sanic、aiohttp)的吞吐量提升 2–4 倍,前提是你的瓶颈在事件循环调度本身,而不是数据库或 JSON 解析这类协程内部操作。
必须在 asyncio.run() 之前设置 policy
这是最常踩的坑——设晚了就等于没设。Python 3.10 默认会懒创建事件循环,一旦 asyncio.run() 或 asyncio.get_event_loop() 被调用过,再调用 asyncio.set_event_loop_policy() 就会抛 RuntimeError: Event loop is closed。
- 正确姿势:在 import 后、任何异步代码执行前,立刻设置
-
uvloop.install()是快捷写法,但本质仍是调用set_event_loop_policy(),同样受此限制 - 如果你用的是
uvicorn启动FastAPI,它默认不走asyncio.run(),所以要在入口脚本里显式设置,不能依赖框架自动加载
FastAPI + uvicorn 场景下怎么生效
很多人以为装了 uvloop 并 import 就行,其实 uvicorn 默认用的是自己的事件循环初始化逻辑,不会自动识别全局 policy。
- 启动时加
--loop uvloop参数:uvicorn main:app --loop uvloop - 或者在代码中手动接管:
import uvloop; uvloop.install()放在if __name__ == "__main__":下,且早于uvicorn.run() - 注意:如果用了
reload=True,某些旧版uvicorn(
哪些地方会悄悄失效
不是所有 asyncio 用法都兼容 uvloop,尤其是一些“看起来很 Python”但实际依赖 selector 实现的边缘操作。
-
asyncio.loop.add_signal_handler()会直接报NotImplementedError—— 改用signal.signal()+loop.call_soon_threadsafe() - 用
asyncio.run_in_executor()调用multiprocessing.Pool时,在 uvloop concurrent.futures.ProcessPoolExecutor - 某些调试工具(如旧版
aiomonitor)读取loop._selector这类私有属性,会崩溃 —— 检查工具是否声明支持 uvloop
验证是否真在跑 uvloop
别信安装日志,要 runtime 看实例类型。
- 加一行诊断代码:
print(asyncio.get_event_loop().__class__.__name__),输出应为Loop(uvloop 的主类名),不是SelectorEventLoop - 在
uvicorn启动日志里找Using uvloop event loop字样(需开启--log-level debug) - 压测对比:用
wrk -t4 -c1000 -d30s http://localhost:8000/,换 uvloop 后 QPS 明显上涨、CPU 使用率下降才是硬指标
真正容易被忽略的点是:uvloop 加速只发生在事件循环密集调度 IO 的路径上;如果你的协程里大量做 time.sleep(1)、json.loads() 或 for i in range(10**6),那换什么循环都没用——得先确认瓶颈在哪,再决定要不要换。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











