uvloop 是基于 libuv 的高性能 asyncio 兼容事件循环,比默认 SelectorEventLoop 快 2–4 倍,因其系统调用更少、调度更紧凑;但对 CPU 密集型或 IO 瓶颈不在事件循环的场景无效。

uvloop 是什么,为什么它比 asyncio 默认循环快
uvloop 是一个用 Cython 编写的高性能事件循环实现,完全兼容 asyncio 接口,但底层基于 libuv(Node.js 和 Rust tokio 也在用的跨平台异步 I/O 库)。它在高并发网络 IO 场景下,尤其是大量短连接、DNS 查询、HTTP 客户端请求时,通常比 CPython 自带的 asyncio.SelectorEventLoop 快 2–4 倍。这不是靠魔法,而是因为 libuv 对 epoll/kqueue/iocp 的封装更精细,系统调用更少,回调调度更紧凑。
但它不是万能加速器:纯 CPU 密集型协程、或协程里频繁做 time.sleep() / asyncio.sleep(),几乎看不出差异;如果你的瓶颈在数据库查询或 JSON 解析,换 uvloop 也无济于事。
如何安全地安装并启用 uvloop
安装只需一行命令,但要注意 Python 版本和平台兼容性:
-
pip install uvloop—— Python 3.8+ 在 Linux/macOS 上基本无坑;Windows 需要 Python 3.11+ 才有稳定支持 - 启用方式有两种,推荐显式替换(避免隐式副作用):
import uvloopasyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) - 必须在
asyncio.run()或asyncio.get_event_loop()调用前设置,否则会报RuntimeError: Event loop is closed - 若项目用了
aiohttp、httpx或fastapi,只要没手动创建asyncio.new_event_loop(),上述两行就足够了
哪些常见场景下 uvloop 反而会出问题
uvloop 不是 drop-in 替换,以下情况容易踩坑:
立即学习“Python免费学习笔记(深入)”;
- 调用
asyncio.loop.run_in_executor()执行阻塞函数时,如果 executor 创建了子进程(如multiprocessing.Pool),某些旧版 uvloop(uvloop>=0.19 可缓解 - 使用
asyncio.loop.add_signal_handler()—— uvloop 不支持信号处理,会直接抛NotImplementedError;改用signal.signal()+asyncio.loop.call_soon_threadsafe() - 依赖
asyncio.loop._selector这类私有属性的调试工具或监控库(比如某些旧版aiomonitor)会失效 - 单元测试中若多次调用
asyncio.run(),且每次都在不同线程里设 policy,可能触发RuntimeError: There is no current event loop in thread—— 测试时建议用pytest-asyncio并禁用全局 policy 设置
验证是否真的生效了
光装了不等于跑起来了。最简单的确认方式是在启动日志或调试时打印当前 loop 类型:
import asyncio import uvloop asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) print(asyncio.get_event_loop().__class__.__name__) # 输出应为 'UVLoop',而不是 'SelectorEventLoop'
更实际的验证是压测对比:用 hey -n 10000 -c 100 http://localhost:8000/health 分别跑默认 loop 和 uvloop 下的 FastAPI/Starlette 服务,看 QPS 和 p99 延迟变化。注意关闭所有后台日志、调试中间件,否则 IO 开销会掩盖 loop 差异。
真正容易被忽略的是:uvloop 加速效果高度依赖你的代码结构。如果每个请求都 await 三次外部 HTTP 调用,但没做并发控制(比如漏了 asyncio.gather()),那瓶颈根本不在 event loop,换啥都白搭。



















