【光子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 依赖,速度更快):
pipinstall"uvicorn[standard]"2. 编写最简单的应用
创建一个名为main.py的文件。
场景 A:配合 FastAPI(最常用)
fromfastapiimportFastAPI app=FastAPI()@app.get("/")defread_root():return{"Hello":"World"}场景 B:原生 ASGI 应用(不依赖框架)
asyncdefapp(scope,receive,send):assertscope['type']=='http'awaitsend({'type':'http.response.start','status':200,'headers':[[b'content-type',b'text/plain']],})awaitsend({'type':'http.response.body','body':b'Hello, Uvicorn!',})3. 启动服务器 (命令行方式)
在终端中运行:
uvicorn main:app --reloadmain: 你的 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 文件底部importuvicornfromfastapiimportFastAPI app=FastAPI()@app.get("/")defroot():return"OK"if__name__=="__main__":# 等同于命令行: uvicorn main:app --reloaduvicorn.run("main:app",host="127.0.0.1",port=8000,reload=True)运行方法:python main.py
6. 生产环境部署建议
在生产环境中(Linux),通常不直接裸跑 Uvicorn,而是使用Gunicorn作为进程管理器来管理 Uvicorn 的 Worker,以获得更好的稳定性和性能。
安装:
pipinstallgunicorn运行命令:
gunicorn main:app -w4-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) 安装(推荐装标准依赖)
最小安装
pipinstalluvicorn最小依赖主要是h11+click。
推荐安装(开发/常见生产更省心)
pipinstall"uvicorn[standard]"standard会额外带上常用性能/体验依赖,例如uvloop、httptools、websockets、watchfiles等;其中watchfiles会让--reload更好用。
3) 跑一个“纯 ASGI”最小示例(不依赖 FastAPI)
新建main.py:
# main.pyasyncdefapp(scope,receive,send):assertscope["type"]=="http"awaitsend({"type":"http.response.start","status":200,"headers":[(b"content-type",b"text/plain"),],})awaitsend({"type":"http.response.body","body":b"Hello, world!",})启动:
uvicorn main:app这里的main:app意思是:从main.py这个模块里导入app这个 ASGI 应用对象。
4) 跑 FastAPI(最常见用法)
main.py:
fromfastapiimportFastAPI app=FastAPI()@app.get("/")defroot():return{"hello":"world"}启动(开发推荐):
uvicorn main:app --reload对外监听(容器/服务器上常用):
uvicorn main:app --host0.0.0.0 --port8000FastAPI 官方文档也强调:--reload非常适合开发,但不应该用于生产环境(更耗资源、也更不稳定)。
5) 最常用参数(够用版)
这些基本能覆盖 80% 场景:
开发
- 自动热重载:
uvicorn main:app --reload--reload会监控文件变化;如果装了watchfiles(uvicorn[standard]会装),还能用更细的 include/exclude。
绑定地址/端口
- 默认只监听本机
127.0.0.1:8000 - 需要局域网/外网访问用:
uvicorn main:app --host0.0.0.0 --port8000--host/--port的默认值与含义见官方 settings。
多进程(生产常用)
uvicorn main:app --workers4注意:--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 --host0.0.0.0 --port8000 - 服务器/容器(多进程):
uvicorn main:app --host0.0.0.0 --port8000--workers4
附:你只需要记住的一条规则
你把“应用对象”暴露为app(或其他名字),然后用模块名:对象名交给 uvicorn就行。
uvloop
这是一个关于uvloop的极简教程。
1. 什么是 uvloop?
一句话介绍:它是 Python 标准库asyncio的高性能替代品。
- 核心:基于
libuv(Node.js 也在用这个库)构建。 - 效果:让 Python 的异步代码运行速度提高2-4 倍,性能直逼 Go 和 Node.js。
- 适用:Linux 和 macOS(不支持 Windows)。
2. 安装
pipinstalluvloop3. 如何使用
使用非常简单,只需要添加两行代码:引入库,然后调用install()。
标准用法(推荐)
importasyncioimportuvloop# 1. 导入asyncdefmain():print("Hello, uvloop!")awaitasyncio.sleep(1)print("Done.")if__name__=="__main__":# 2. 安装 uvloop 策略# 这行代码会将 asyncio 的默认事件循环替换为 uvloopuvloop.install()asyncio.run(main())4. 在 Web 框架中使用
如果你是做 Web 开发(FastAPI, Sanic, Django 等),通常不需要手动写代码。
Uvicorn (FastAPI 的默认服务器):
Uvicorn默认就会检测并使用uvloop。只要你安装了它,Uvicorn 就会自动启用。# 只要安装了 uvloop,启动时不需要额外配置pipinstalluvloop 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:importuvloop uvloop.install()exceptImportError: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 pipinstall-U pip python -m pipinstalluvloopuvloop 当前版本线(截至2026-01-09)在 PyPI 上显示Requires: Python >= 3.8.1,并且能看到 0.22.1(2025-10-16 上传)的发布信息。
3)最推荐的“极��用法”:uvloop.run()
从 uvloop0.18开始,官方 README 推荐直接用uvloop.run()作为入口(它会把asyncio.run()配置成使用 uvloop)。
main.py
importasyncioimportuvloopasyncdefmain():awaitasyncio.sleep(0.1)print("hello from uvloop")uvloop.run(main())运行:
python main.py4)如果你想更“贴近 asyncio 官方方向”:loop_factory(Python 3.12+)
Python 文档里说明:asyncio.run()在3.12增加了loop_factory参数,并且官方也提到policy 机制在 3.14 已弃用、计划 3.16 移除,更推荐用loop_factory来配置事件循环。
所以你也可以这样写(本质上和 uvloop.run 的思路一致):
importasyncioimportuvloopasyncdefmain():...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.1call_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.2call_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.3call_later()/call_at():用uv_timer_t实现定时器
asyncio 的延迟调度本质是“定时器堆/最小堆 + 到期触发”。libuv 里对应的就是uv_timer_t:可以uv_timer_start(timeout, repeat),到期后回调。
uvloop 中的TimerHandle会创建一个UVTimer并启动它,然后把这个 timer handle 记录在loop._timers集合里用于生命周期管理。
3.4add_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),我也可以把这套映射画成一页速查图,方便你写分享/做内部培训。