欢迎光临
我们一直在努力

【光子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
  • 兼容性: 虽然它力求与 asyncio 100% 兼容,但在极少数使用底层 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),我也可以把这套映射画成一页速查图,方便你写分享/做内部培训。

    赞(0)
    未经允许不得转载:171主机测评 » 【光子AI / Photon.AI】uvicorn 极简教程:Python 的 ASGI Web 服务器
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址