【光子AI / Photon.AI】uvicorn 极简教程:Python 的 ASGI Web 服务器

【光子AI / Photon.AI】uvicorn 极简教程:Python 的 ASGI Web 服务器
Uvicorn is an ASGI web server implementation for Python.
- https://github.com/AIGeniusInstitute/uvicorn
- https://uvicorn.dev/
这是一个 Uvicorn 的极简上手教程。Uvicorn 是一个基于 uvloop 和 httptools 构建的超快 ASGI 服务器,通常用于运行 FastAPI 或 Starlette 应用。
文章目录
- 【光子AI / Photon.AI】uvicorn 极简教程:Python 的 ASGI Web 服务器
- 1. 安装
- 2. 编写最简单的应用
- 3. 启动服务器 (命令行方式)
- 4. 常用参数速查
- 5. 代码中启动 (脚本方式)
- 6. 生产环境部署建议
- ============================================
- 1) Uvicorn 是什么(1 句话)
- 2) 安装(推荐装标准依赖)
- 最小安装
- 推荐安装(开发/常见生产更省心)
- 3) 跑一个“纯 ASGI”最小示例(不依赖 FastAPI)
- 4) 跑 FastAPI(最常见用法)
- 5) 最常用参数(够用版)
- 开发
- 绑定地址/端口
- 多进程(生产常用)
- 6) 放到反向代理(Nginx/Caddy/云负载均衡)后面的要点(极简但关键)
- 7) 一句话“抄作业”模板
- 附:你只需要记住的一条规则
- ==================uvloop==================
- 1. 什么是 uvloop?
- 2. 安装
- 3. 如何使用
- 标准用法(推荐)
- 4. 在 Web 框架中使用
- 5. Jupyter Notebook 中使用
- 6. 注意事项
- 总结
- 1)uvloop 是什么(一句话)
- 2)安装(最小步骤)
- 3)最推荐的“极��用法”:uvloop.run()
- 4)如果你想更“贴近 asyncio 官方方向”:loop_factory(Python 3.12+)
- 5)在 Web 框架里用(以 Uvicorn/FastAPI 为例)
- 6)三个最常见坑(极简版排雷)
- 坑 A:Windows / PyPy
- 坑 B:要在“创建事件循环之前”设置好
- 坑 C:Jupyter/已有事件循环环境
- 7)什么时候用 uvloop 最划算(快速判断)
- 1. 核心引擎:libuv (站在巨人的肩膀上)
- 2. 桥梁技术:Cython (去掉了中间商)
- 3. 性能优化的“黑魔法”
- A. 零损耗的内存管理 (Memory Management)
- B. 函数调用开销最小化
- C. 高效的句柄 (Handle) 管理
- 4. 架构对比图
- 总结
- 1)uvloop 的本质:用 libuv 重新实现了 asyncio 的 EventLoop
- 2)libuv 的事件循环模型(理解 uvloop 的关键)
- 3)uvloop 怎么把 asyncio 的语义映射到 libuv(核心机制逐个拆)
- 3.1 `call_soon()`:把回调放进 ready 队列,下一轮循环执行
- 3.2 `call_soon_threadsafe()`:用 `uv_async_t` 跨线程唤醒 loop
- 3.3 `call_later()` / `call_at()`:用 `uv_timer_t` 实现定时器
- 3.4 `add_reader()` / `add_writer()`:用 `uv_poll_t` 监听 fd 可读/可写
- 3.5 DNS:`getaddrinfo`/`getnameinfo` 走 libuv request(并用线程池做阻塞部分)
- 3.6 信号(signals):用 “self-pipe + wakeup_fd” 把 signal 变成可读事件
- 4)为什么 uvloop 往往更快(从机制上解释,不靠玄学)
- 5)你想读源码/定位机制时,从哪些文件入手(最短路径)
1. 安装
建议安装标准版(包含 Cython 依赖,速度更快):
pip install "uvicorn[standard]"
2. 编写最简单的应用
创建一个名为 main.py 的文件。
场景 A:配合 FastAPI(最常用)
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
场景 B:原生 ASGI 应用(不依赖框架)
async def app(scope, receive, send):
assert scope['type'] == 'http'
await send({
'type': 'http.response.start',
'status': 200,
'headers': [[b'content-type', b'text/plain']],
})
await send({
'type': 'http.response.body',
'body': b'Hello, Uvicorn!',
})
3. 启动服务器 (命令行方式)
在终端中运行:
uvicorn main:app --reload
main: 你的 Python 文件名(main.py)。app: 文件中实例化的对象名(比如app = FastAPI())。--reload: 开发模式神器。代码修改后自动重启服务器。
4. 常用参数速查
| 参数 | 说明 | 示例 |
|---|---|---|
--reload | 开发模式,代码变动自动重启 | uvicorn main:app --reload |
--host | 绑定 IP。0.0.0.0 允许外网访问 | uvicorn main:app --host 0.0.0.0 |
--port | 指定端口(默认 8000) | uvicorn main:app --port 8080 |
--workers | 启动的工作进程数(生产环境用) | uvicorn main:app --workers 4 |
5. 代码中启动 (脚本方式)
如果你想直接运行 Python 文件来启动服务器(方便调试):
# main.py 文件底部
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return "OK"
if __name__ == "__main__":
# 等同于命令行: uvicorn main:app --reload
uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True)
运行方法:python main.py
6. 生产环境部署建议
在生产环境中(Linux),通常不直接裸跑 Uvicorn,而是使用 Gunicorn 作为进程管理器来管理 Uvicorn 的 Worker,以获得更好的稳定性和性能。
安装:
pip install gunicorn
运行命令:
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker
-w 4: 开启 4 个 Worker 进程。-k ...: 指定使用 Uvicorn 的 Worker 类。
总结:
开发用 uvicorn main:app --reload,生产用 Gunicorn 带 Uvicorn Worker。
============================================
下面是一份 Uvicorn 极简教程(从 0 到跑起来),并在末尾附一个“最常用的进阶参数清单”,够用但不啰嗦。
1) Uvicorn 是什么(1 句话)
Uvicorn 是 Python 的 ASGI Web 服务器,用来跑 FastAPI / Starlette / 任何 ASGI 应用,支持 HTTP/1.1 和 WebSocket。
2) 安装(推荐装标准依赖)
最小安装
pip install uvicorn
最小依赖主要是 h11 + click。
推荐安装(开发/常见生产更省心)
pip install "uvicorn[standard]"
standard 会额外带上常用性能/体验依赖,例如 uvloop、httptools、websockets、watchfiles 等;其中 watchfiles 会让 --reload 更好用。
3) 跑一个“纯 ASGI”最小示例(不依赖 FastAPI)
新建 main.py:
# main.py
async def app(scope, receive, send):
assert scope["type"] == "http"
await send({
"type": "http.response.start",
"status": 200,
"headers": [
(b"content-type", b"text/plain"),
],
})
await send({
"type": "http.response.body",
"body": b"Hello, world!",
})
启动:
uvicorn main:app
这里的 main:app 意思是:从 main.py 这个模块里导入 app 这个 ASGI 应用对象。
4) 跑 FastAPI(最常见用法)
main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"hello": "world"}
启动(开发推荐):
uvicorn main:app --reload
对外监听(容器/服务器上常用):
uvicorn main:app --host 0.0.0.0 --port 8000
FastAPI 官方文档也强调:--reload 非常适合开发,但不应该用于生产环境(更耗资源、也更不稳定)。
5) 最常用参数(够用版)
这些基本能覆盖 80% 场景:
开发
- 自动热重载:
uvicorn main:app --reload--reload会监控文件变化;如果装了watchfiles(uvicorn[standard]会装),还能用更细的 include/exclude。
绑定地址/端口
- 默认只监听本机
127.0.0.1:8000 - 需要局域网/外网访问用:
uvicorn main:app --host 0.0.0.0 --port 8000--host/--port的默认值与含义见官方 settings。
多进程(生产常用)
uvicorn main:app --workers 4
注意:--workers 和 --reload 互斥,不能同时用。
6) 放到反向代理(Nginx/Caddy/云负载均衡)后面的要点(极简但关键)
如果你在 Nginx 后面跑 Uvicorn,官方给了典型 Nginx 配置示例,并建议可用 UNIX Socket(--uds)连接更稳。
同时,“真实客户端 IP / http vs https” 往往靠 X-Forwarded-For、X-Forwarded-Proto 这类头传递;Uvicorn 支持读取这些,但必须配置你信任哪些代理来源(否则会被伪造)。相关参数是 --proxy-headers 与 --forwarded-allow-ips。
7) 一句话“抄作业”模板
- 本地开发:
uvicorn main:app --reload - 服务器/容器(单进程):
uvicorn main:app --host 0.0.0.0 --port 8000 - 服务器/容器(多进程):
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
附:你只需要记住的一条规则
你把“应用对象”暴露为 app(或其他名字),然后用 模块名:对象名 交给 uvicorn 就行。
uvloop
这是一个关于 uvloop 的极简教程。
1. 什么是 uvloop?
一句话介绍: 它是 Python 标准库 asyncio 的高性能替代品。
- 核心: 基于
libuv(Node.js 也在用这个库)构建。 - 效果: 让 Python 的异步代码运行速度提高 2-4 倍,性能直逼 Go 和 Node.js。
- 适用: Linux 和 macOS(不支持 Windows)。
2. 安装
pip install uvloop
3. 如何使用
使用非常简单,只需要添加两行代码:引入库,然后调用 install()。
标准用法(推荐)
import asyncio
import uvloop # 1. 导入
async def main():
print("Hello, uvloop!")
await asyncio.sleep(1)
print("Done.")
if __name__ == "__main__":
# 2. 安装 uvloop 策略
# 这行代码会将 asyncio 的默认事件循环替换为 uvloop
uvloop.install()
asyncio.run(main())
4. 在 Web 框架中使用
如果你是做 Web 开发(FastAPI, Sanic, Django 等),通常不需要手动写代码。
-
Uvicorn (FastAPI 的默认服务器):
Uvicorn 默认就会检测并使用uvloop。只要你安装了它,Uvicorn 就会自动启用。# 只要安装了 uvloop,启动时不需要额外配置 pip install uvloop uvicorn main:app如果想强制使用或禁用:
uvicorn main:app --loop uvloop或--loop asyncio。 -
Sanic:
Sanic 默认内置并使用uvloop,无需额外操作。 -
Gunicorn:
如果使用 Gunicorn 部署 Uvicorn worker:gunicorn -k uvicorn.workers.UvicornWorker main:app它也会自动继承 Uvicorn 的行为(自动使用 uvloop)。
5. Jupyter Notebook 中使用
在 Jupyter 或 IPython 中,因为环境已经在这个 Event Loop 中运行,直接 uvloop.install() 可能会报错或无效。通常在 Notebook 中做实验不需要替换 Loop,但在生产代码中记得加上。
6. 注意事项
- 操作系统限制:
uvloop不支持 Windows。如果在 Windows 上开发,请使用标准asyncio,部署到 Linux 服务器时再安装uvloop。- 技巧: 可以用
try...except兼容:try: import uvloop uvloop.install() except ImportError: pass # Windows 下没有 uvloop,回退到标准 asyncio
- 技巧: 可以用
- 兼容性: 虽然它力求与
asyncio100% 兼容,但在极少数使用底层 API 的库中可能会有问题(非常罕见)。
总结
安装 uvloop -> 代码开头加 uvloop.install() -> 享受加速。
下面是一个uvloop 极简教程:目标是让你在 1~3 分钟内把 asyncio 的事件循环换成 uvloop,并知道在不同 Python 版本/常见框架里怎么用。
1)uvloop 是什么(一句话)
uvloop 是 asyncio 默认事件循环的“更快替代品”,底层基于 libuv;官方 README 给出的经验结论是:很多网络场景里能让 asyncio 快 2~4 倍。
2)安装(最小步骤)
python -m pip install -U pip
python -m pip install uvloop
uvloop 当前版本线(截至 2026-01-09)在 PyPI 上显示 Requires: Python >= 3.8.1,并且能看到 0.22.1(2025-10-16 上传)的发布信息。
3)最推荐的“极��用法”:uvloop.run()
从 uvloop 0.18 开始,官方 README 推荐直接用 uvloop.run() 作为入口(它会把 asyncio.run() 配置成使用 uvloop)。
main.py
import asyncio
import uvloop
async def main():
await asyncio.sleep(0.1)
print("hello from uvloop")
uvloop.run(main())
运行:
python main.py
4)如果你想更“贴近 asyncio 官方方向”:loop_factory(Python 3.12+)
Python 文档里说明:asyncio.run() 在 3.12 增加了 loop_factory 参数,并且官方也提到 policy 机制在 3.14 已弃用、计划 3.16 移除,更推荐用 loop_factory 来配置事件循环。
所以你也可以这样写(本质上和 uvloop.run 的思路一致):
import asyncio
import uvloop
async def main():
...
asyncio.run(main(), loop_factory=uvloop.new_event_loop)
5)在 Web 框架里用(以 Uvicorn/FastAPI 为例)
如果你用的是 Uvicorn:
- 直接指定:
uvicorn main:app --loop uvloop - 或者默认
--loop auto:如果安装了 uvloop,会自动优先选 uvloop;没有则回退到 asyncio。
6)三个最常见坑(极简版排雷)
坑 A:Windows / PyPy
很多生态文档会直接写明:uvloop 不兼容 Windows 或 PyPy,因此这些平台不可用(常见报错就是 “uvloop does not support Windows at the moment”)。
坑 B:要在“创建事件循环之前”设置好
无论用 uvloop.run() 还是 loop_factory,都应该作为程序入口最早发生;不要等 event loop 已经跑起来了再切。
坑 C:Jupyter/已有事件循环环境
asyncio.run()(以及 uvloop.run())都不能在“同线程已有运行中的事件循环”里再调用;Notebook 里更推荐直接 await main()(但这就不算“脚本入口极简”那种用法了)。
7)什么时候用 uvloop 最划算(快速判断)
- 很划算:高并发网络 I/O(HTTP 服务、网关、爬虫、长连接、代理、消息转发等)——uvloop 主打的就是 event loop 调度和 I/O 性能。
- 不神奇:CPU 密集型(纯计算/GIL 限制)——换 uvloop 不会把 CPU 运算变快,通常要靠多进程/原生扩展/向量化等。
如果你只记一条:脚本入口用 uvloop.run(main);上框架(Uvicorn)就 装上 uvloop 并让 Uvicorn 选 uvloop。
===============================
uvloop 之所以快,并不是因为它使用了什么魔法,而是因为它通过 Cython 将 Python 标准库 asyncio 的核心逻辑(事件循环)用 C 语言 重新写了一遍,底层则由高性能的 libuv 驱动。
可以将它的原理拆解为三个核心支柱:核心引擎 (libuv)、桥梁技术 (Cython) 和 极度优化的内存管理。
1. 核心引擎:libuv (站在巨人的肩膀上)
uvloop 的名字就来源于 libuv。
- 什么是 libuv? 它是 Node.js 的核心异步 I/O 库。它非常成熟、稳定且极快。
- 它做什么? 它负责处理底层的操作系统通知。比如“网卡收到数据了”、“文件读取完毕了”。
- 为什么快? 它在 Linux 上使用
epoll,在 macOS 上使用kqueue,这些是操作系统能够提供的最高效的 I/O 通知机制。
对比: Python 原生
asyncio虽然也支持epoll,但其内部封装逻辑较重。uvloop直接利用了经过 Node.js 全球海量并发验证过的libuv。
2. 桥梁技术:Cython (去掉了中间商)
这是 uvloop 最关键的实现细节。uvloop 不是简单地用 Python 调 C 库,而是用 Cython 编写的。
- 完全替换:
uvloop并不是“修补”了asyncio,而是实现了asyncio.AbstractEventLoop接口的一个全新类。 - 绕过 Python 解释器:
- 原生 asyncio: 事件循环的调度逻辑主要是 Python 代码。每次循环、每个回调,都要在 Python 解释器层面跑很多指令,产生大量 CPU 开销。
- uvloop: 整个事件循环的“心跳”是在 C 语言层面(通过 Cython 编译)运行的。只有到了必须执行用户写的 Python 回调函数(比如你的
async def)时,它才会切换回 Python。
3. 性能优化的“黑魔法”
仅仅用 C 重写并不足以达到现在的速度,uvloop 的作者(MagicStack 团队)在实现细节上做了大量优化:
A. 零损耗的内存管理 (Memory Management)
在异步编程中,会频繁创建小的对象(比如 Future 对象、Task 对象、Handle 对象)。
- 原生 asyncio: 每次操作都可能分配新的 Python 对象,造成内存碎片和 GC(垃圾回收)压力。
- uvloop: 使用了 Free list(空闲链表) 技术。它会重用已经被废弃的 C 结构体内存,而不是反复向操作系统申请和释放内存。这极大地减少了内存分配的开销。
B. 函数调用开销最小化
Python 的函数调用是有开销的(参数解包、栈帧创建等)。
uvloop在内部处理libuv的回调时,尽可能保持在 C 层面流转,只有在最后一步才将数据转化为 Python 对象传给用户代码。
C. 高效的句柄 (Handle) 管理
uvloop 针对不同类型的 I/O(TCP, UDP, Pipe, Signal)进行了专门的优化路径,而不是使用通用的低效封装。
4. 架构对比图
为了直观理解,我们可以对比一下调用路径:
原生 asyncio 的路径:
Python 代码 -> asyncio (Python循环) -> Select/Epoll (C模块) -> 操作系统
^ |
|______________________________________|
大量 Python 字节码执行,频繁的对象创建
uvloop 的路径:
Python 代码 -> uvloop (C/Cython循环) -> libuv (C库) -> 操作系统
^ |
|___________________________________|
几乎纯 C 的路径,极少的 Python 介入,内存复用
总结
uvloop 的原理可以概括为:
- 底子好: 用了 Node.js 同款的高性能
libuv做底盘。 - 写得好: 用
Cython把事件循环逻辑“编译”成了 C 语言,消除了 Python 解释器的慢速循环开销。 - 算得精: 极致的内存复用和对象池技术,减少了垃圾回收的压力。
这就是为什么只加了两行代码,Python 就能跑得像 Go 一样快的原因。
==========================================
下面按“从 asyncio 的抽象 → libuv 的事件循环模型 → uvloop 怎么把两者粘起来”的顺序,把 uvloop 背后的实现原理讲清楚(尽量贴近源码结构,但不要求你读 Cython/CPython 才能理解)。
1)uvloop 的本质:用 libuv 重新实现了 asyncio 的 EventLoop
asyncio(PEP 3156)把“事件循环”设计成可插拔组件:只要你实现 asyncio.AbstractEventLoop 这套接口,就能替换默认 event loop。uvloop 做的就是:实现完整的 asyncio event loop API,但底层不走 Python 默认 selector 循环,而是走 libuv。
同时,uvloop 是用 Cython 写的扩展模块(不是纯 Python),并且构建时会拉取/包含 libuv 源码(git clone --recursive 会把 libuv 也拉下来)。这解释了它为什么能把大量“循环内热路径”挪到 C 层去跑。
2)libuv 的事件循环模型(理解 uvloop 的关键)
libuv 的设计核心是两类对象:
- handles(句柄):长期存在的“事件源/监视器”,比如 timer、TCP server、poll(fd)、async 等。
- requests(请求):短生命周期的一次性操作,比如一次 write request、一次 getaddrinfo 请求等。
libuv 的循环迭代(tick)大致按固定阶段执行:先跑 due timers、再处理 pending callbacks、idle/prepare、计算 poll 超时、阻塞等待 I/O、check、close callbacks……并且 I/O poll 的底层会用平台最优机制(Linux epoll、macOS/BSD kqueue、Windows IOCP 等)。
你可以把 libuv 看成一个“高性能反应器(reactor)内核”:负责等待事件、在事件发生时回调;上层库负责把“用户想要的抽象”(比如 asyncio 的 Task/Future/transport/protocol)映射到这些回调上。
3)uvloop 怎么把 asyncio 的语义映射到 libuv(核心机制逐个拆)
下面是最重要的一张“映射表”。我会用 uvloop 的 Cython 源码片段(旧版本 0.9.1 但机制一致) + libuv 官方文档来解释每一项。
3.1 call_soon():把回调放进 ready 队列,下一轮循环执行
asyncio 的最小调度原语就是 loop.call_soon(cb, ...):把回调塞到“待执行队列”里,尽快执行。
uvloop 的做法也是类似:维护一个 _ready 队列;关键在于——它用 libuv 的某个 handle(典型是 idle/prepare/check 这类“每轮都会被调用的钩子”)来驱动“从 _ready 队列里弹出回调并执行”。在源码里能看到 _on_idle 会去消费 ready 队列并执行 handle。
为什么要靠 libuv 的 handle?因为底层循环是 libuv 在跑,uvloop 必须把“执行 Python 回调”挂到 libuv 的 tick 阶段里。
3.2 call_soon_threadsafe():用 uv_async_t 跨线程唤醒 loop
asyncio 要求 call_soon_threadsafe 能从别的线程把任务塞进 loop,并唤醒正在 poll 的事件循环。
libuv 专门提供了 uv_async_t:它允许你从任意线程调用 uv_async_send() 唤醒事件循环,然后让回调在 loop 所在线程执行(并且会发生“合并 coalesce”,多次 send 可能只触发一次回调)。
uvloop 里对应的实现就是:
call_soon_threadsafe()先把回调入队;- 然后调用一个
handler_async.send()去唤醒 loop。
而handler_async的底层正是uv_async_t:初始化用uv_async_init,唤醒用uv_async_send。
一句话总结:call_soon_threadsafe = 入队 + uv_async_send 唤醒。
3.3 call_later() / call_at():用 uv_timer_t 实现定时器
asyncio 的延迟调度本质是“定时器堆/最小堆 + 到期触发”。libuv 里对应的就是 uv_timer_t:可以 uv_timer_start(timeout, repeat),到期后回调。
uvloop 中的 TimerHandle 会创建一个 UVTimer 并启动它,然后把这个 timer handle 记录在 loop._timers 集合里用于生命周期管理。
3.4 add_reader() / add_writer():用 uv_poll_t 监听 fd 可读/可写
asyncio 允许你把一个 fd(或 socket)注册到事件循环:可读时回调、可写时回调。
libuv 提供 uv_poll_t 来做这件事:监听 fd 的 readable/writable 等事件。
uvloop 的实现是:为每个 fd 维护一个 UVPoll 对象;如果 fd 第一次出现就 UVPoll.new(self, fd),然后 start_reading(handle) 或 start_writing(handle)。这在源码里是非常直接的:
小提示:libuv 文档也提醒了
uv_poll_t的一些限制(比如同一 socket 不能多个 poll handle,否则可能 busyloop)。这也是为什么 uvloop 会自己维护“fd→poll handle”的唯一映射。
3.5 DNS:getaddrinfo/getnameinfo 走 libuv request(并用线程池做阻塞部分)
asyncio 的 DNS(以及很多库的域名解析)经常是性能/延迟热点。
libuv 提供 uv_getaddrinfo / uv_getnameinfo 的异步版本。
同时 libuv 明确说明:它内部有一个全局线程池,会用于 文件系统操作以及 getaddrinfo/getnameinfo 这类本质上可能阻塞的调用。默认线程数是 4,可通过 UV_THREADPOOL_SIZE 调整(最大 1024)。
uvloop 的 dns.pyx 里能看到它直接调用:uv.uv_getaddrinfo(loop.uvloop, ..., __on_addrinfo_resolved, ...),完成后回调。
3.6 信号(signals):用 “self-pipe + wakeup_fd” 把 signal 变成可读事件
asyncio 在 Unix 上的 signal 处理,核心思路是:信号到来时不要在信号处理器里做复杂逻辑,而是把它转成“某个 fd 可读”事件,让事件循环在安全上下文里处理。
uvloop 也遵循这个策略:它创建 socketpair(),并用 signal.set_wakeup_fd() 把信号通知写入到某一端;然后对另一端 add_reader,当 fd 可读就读出来并分发信号回调。源码里能看到 _setup_signals() 用 socketpair + set_wakeup_fd,以及 _recv_signals_start() 把 self-pipe 注册为 reader。
4)为什么 uvloop 往往更快(从机制上解释,不靠玄学)
uvloop 性能优势通常来自两层叠加:
-
“循环内热路径”更多在 C 层:uvloop 用 Cython + libuv,把大量“每次 tick 都会发生的工作”(fd 事件分发、定时器触发、唤醒机制、部分 transport/write 逻辑)放到更低层执行,减少 Python 函数调度/对象开销。
-
libuv 本身是成熟的高性能事件循环内核:它的 poll 后端、定时器、handle/request 模型在 Node.js 等生态中长期打磨,并且明确了循环阶段与线程模型(网络 I/O 单线程;文件/DNS 用线程池补齐异步)。
注意:这不意味着“任何程序都变快”。CPU 密集型任务瓶颈不在 event loop;而且如果你的瓶颈在协议解析/业务逻辑(例如 HTTP parser 很慢),换 loop 也救不了。uvloop 官方文章里也提过类似现象(瓶颈可能在 HTTP 解析器而非 I/O)。
5)你想读源码/定位机制时,从哪些文件入手(最短路径)
如果你准备进一步刨源码,按这个顺序最容易建立整体感:
loop.pyx:loop 的初始化、call_soon_threadsafe唤醒、signals self-pipe、reader/writer 注册等(你会看到uv_loop_init、uv_run、handler_async.send()、_add_reader/_add_writer)。handles/async_.pyx:uv_async_t封装,理解“跨线程唤醒”的 C 层路径。cbhandles.pyx:TimerHandle如何用UVTimer(libuv timer)实现。dns.pyx:DNS request 如何对接 libuv。poll/udp/tcp/stream等:transport/protocol 如何把 socket I/O 对接到 libuv 的 handle。
如果你希望我用一张更“工程化”的图(比如把 asyncio API 分成 Scheduling / Timers / FD Watchers / Network Transports / DNS / Signals / Subprocess,并画出它们对应的 libuv handle/request),我也可以把这套映射画成一页速查图,方便你写分享/做内部培训。








