FastAPI 性能基准:TechEmpower 结论背后的 Uvicorn、Starlette 与 FastAPI 三层性能阶梯
本文基于 FastAPI 官方文档中的基准测试章节(docs/de/docs/benchmarks.md),解读独立 TechEmpower 基准中 FastAPI 的真实性能定位,讲清 Uvicorn → Starlette → FastAPI 三层框架的性能阶梯关系,并结合仓库内置的基准测试套件(tests/benchmarks/)说明 FastAPI 的性能开销到底花在哪里、如何被衡量。
基准测试结论:FastAPI 处在什么位置
独立的 TechEmpower 基准测试表明,运行在 Uvicorn 之下的 FastAPI 应用是可用的 Python 框架中最快的之一,性能仅次于 Starlette 和 Uvicorn 本身——而后两者恰恰是 FastAPI 内部所依赖和使用的组件。README 中的 Performance 章节(README.md)也复述了这一结论。
但要正确理解这个结果,必须理解 FastAPI 的技术栈分层,否则很容易把不同层级的工具放在同一张榜单上做出错误对比。
三层技术栈的性能阶梯
FastAPI 的性能层级关系可以概括为如下嵌套结构(源自基准文档的原文层级说明):
- Uvicorn:一个 ASGI 服务器
- Starlette:(运行于 Uvicorn 之上)一个 Web 微框架
- FastAPI:(运行于 Starlette 之上)一个带有数据验证、序列化、自动文档等额外能力的 API 微框架
- Starlette:(运行于 Uvicorn 之上)一个 Web 微框架
这一层级关系在仓库源码中有直接证据:fastapi/applications.py 中 FastAPI 类直接继承自 Starlette,而 pyproject.toml 声明了核心依赖 starlette>=0.46.0 和 pydantic>=2.9.0,标准安装组(standard)中还包含 uvicorn[standard](pyproject.toml、pyproject.toml)。因此"FastAPI 不可能比 Starlette 更快"不是猜测,而是继承关系决定的必然:它每一层都在调用下层提供的能力,叠加了更多代码。
为什么简单的基准测试会"失真"
文档指出了一个常见误区:查看基准测试时,人们习惯把不同类别的工具放在同一水平线上对比,尤其是把 Uvicorn、Starlette、FastAPI 混在一起比较(以及与其他许多工具比较)。
基本原则是:工具解决的问题越简单,其基准成绩越好;而大多数基准测试并不会测试工具所提供的额外功能。按正确的对比基准,三层工具应分别与同层级的工具比较:
- Uvicorn
- 拥有最好的成绩是理所当然的——除了服务器本身几乎没有额外代码。
- 你不会直接把应用写在 Uvicorn 上。那样意味着你的代码必须包含至少与 Starlette(或 FastAPI)所提供的等量的全部代码。如果真这么做,最终应用将承受与使用框架完全相同的开销,却损失了框架带来的更少代码和更少错误。
- 正确对比对象:Daphne、Hypercorn、uWSGI 等应用服务器。
- Starlette
- 成绩仅次于 Uvicorn。Starlette 本身依赖 Uvicorn 运行,它"变慢"只可能是因为要执行更多代码。
- 它提供了构建简单 Web 应用的工具:基于路径的 Routing 等。
- 正确对比对象:Sanic、Flask、Django 等 Web 框架(或微框架)。
- FastAPI
- 正如 Starlette 使用 Uvicorn 而无法比其更快,FastAPI 使用 Starlette 也同样不可能比其更快。
- FastAPI 在 Starlette 之上提供构建 API 时几乎总是需要的额外能力:数据验证、序列化。使用它们还能免费获得自动文档——自动文档的生成发生在应用启动时,而不是每次请求时,因此不会对运行中的应用造成任何额外开销。
- 关键点:如果不使用 FastAPI,转而直接使用 Starlette(或 Sanic、Flask、Responder 等工具),你就必须自己实现全部的数据验证与序列化。最终应用依然会背负与用 FastAPI 构建时相同的开销。而且在很多场景中,数据验证与序列化本身就是应用代码中占比最大的部分。
- 正确对比对象:自带数据验证、序列化与文档能力的 Web 应用框架(或工具组合),例如 Flask-apispec、NestJS、Molten 等。
由此得出的实际结论是:使用 FastAPI 能省下开发时间、代码行数和错误,而性能大概率与你不用它、自己手写全部验证与序列化代码时相同(甚至更好)。
仓库内置基准测试:FastAPI 如何量化自己的开销
上述"开销不可避免"的论断在仓库中并不是空口无凭——FastAPI 自带一个基准测试目录 tests/benchmarks/,用 pytest-codspeed 框架对关键性能路径做回归测量。
通用请求性能基准
tests/benchmarks/test_general_performance.py 构造了一组覆盖 FastAPI 核心处理路径的端点,系统性地对比不同实现方式的吞吐差异:
| 维度 | 被测端点 | 说明 |
|---|---|---|
| 同步 vs 异步 | /sync/* 与 /async/* |
同一逻辑分别用 def 与 async def 实现 |
有无 response_model |
*-dict-no-response-model / *-dict-with-response-model 等 |
返回裸 dict 与返回 Pydantic 模型实例的开销对比 |
| 载荷规模 | /sync/large-receive、/async/large-receive 及 8 个 large 输出端点 |
300 条记录、每条含 25 个 values 的大 JSON 载荷,覆盖接收与序列化两个方向 |
基准载荷 LARGE_PAYLOAD(300 个 item,每个含 id、name、values、meta 字段)直接测量了"大响应体序列化"这一 FastAPI 开销的主要来源(tests/benchmarks/test_general_performance.py#L17-L38)。每个测试在正式测量前都会先发一次预热请求(warmup),保证测得的是稳态性能(tests/benchmarks/test_general_performance.py#L190-L211)。这些端点背后正是 fastapi/routing.py 中的 serialize_response 与 fastapi/routing.py 中继承 Starlette Route 的 APIRoute——它们决定了验证和序列化代码的实际执行位置。
OpenAPI 生成性能基准
tests/benchmarks/test_openapi.py 专门基准测试 OpenAPI 模式生成的耗时。其辅助代码 tests/benchmarks/utils.py 构造了一个含 20 个路由、共享一条 101 层深度依赖链(dependency_100 → … → dependency_0)的应用,然后反复调用 app.openapi()(先置空 app.openapi_schema 缓存以强制重新生成),验证生成的 schema 中每个动态路由都正确携带 query_value 查询参数。这条基准的意义在于:它印证了文档中"自动文档在启动时生成"的说法——schema 生成是一次性的启动成本,仓库甚至专门对它做回归监控;运行中的请求不会触碰这条路径。
如何运行这些基准
从源码结构看,这些基准默认不会执行:两个测试文件开头都检查 --codspeed 参数,未提供时整模块跳过("Benchmark tests are skipped by default; run with --codspeed.",见 tests/benchmarks/test_general_performance.py#L11-L15)。对应的 pytest-codspeed >=4.3.0 依赖声明在 pyproject.toml 的 tests 依赖组中,而 pyproject.toml 的 coverage 配置将 tests/benchmarks/* 排除在覆盖率统计之外,说明它们定位为独立运行的性能工具而非常规测试。实际执行需借助 codspeed 的 runner 命令传入 --codspeed,普通 pytest 或 bash scripts/test.sh 流程会自动跳过。
小结:如何正确看待 FastAPI 的速度
- FastAPI 不是"最底层",所以基准榜上落后于 Uvicorn 和 Starlette 是架构上的必然,而非实现低效;
- 与 FastAPI 公平比较的对象是"框架 + 手写验证/序列化"的完整方案(Flask-apispec、NestJS 一类),而不是裸服务器或微框架;
- FastAPI 提供的验证、序列化与启动时生成的 OpenAPI 文档,恰好构成了多数 API 应用代码的主体,这部分开销无论用什么框架都逃不掉——FastAPI 只是把它变成显式的、可被
tests/benchmarks/这类基准持续监控的开销。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00