3. Python Web 框架选型:Flask vs FastAPI vs Sanic

在构建低延迟评分接口时,Web 框架的 I/O 模型、路由开销与序列化效率直接决定接口的尾延迟(P99)与吞吐量(RPS)。本章从异步支持、请求生命周期、序列化机制三个维度,对 Flask、FastAPI、Sanic 进行横向对比,并给出不同场景下的选型建议。

3.1 框架核心差异总览

特性 Flask 2.x FastAPI 0.100+ Sanic 23+
异步支持 WSGI + 可选 async 视图 ASGI 原生异步 ASGI 原生异步
请求模型 同步/线程池 事件循环 + await 事件循环 + await
序列化引擎 无内置,常用 Marshmallow Pydantic v2(Rust 核心) 无内置,常用 Pydantic / orjson
路由性能 线性匹配,中等 基于 Trie 树,高 基于 Radix Tree,极高
内置校验 无 Pydantic 模型校验 无
自动文档 需扩展(Flask-RESTx) OpenAPI + Swagger 原生 需扩展
生产部署 Gunicorn + 多 worker Uvicorn / Gunicorn + Uvicorn Sanic 内置多 worker
选型第一原则:如果团队已有 Flask 技术栈且延迟要求不高(P99 < 500ms),Flask 仍可胜任;若目标为 P99 < 50ms 的高并发评分接口,优先考虑 FastAPI 或 Sanic。

3.2 性能对比:基准测试数据

以下数据基于相同硬件环境(4 核 8G,Python 3.11),使用 wrk 压测 30 秒,模拟 100 并发,接口返回固定 JSON 响应 {"status": "ok"}。

指标 Flask (Gunicorn 4 workers) FastAPI (Uvicorn 4 workers) Sanic (4 workers)
RPS(请求/秒) 4,200 12,800 15,600
P50 延迟 23 ms 7.8 ms 6.4 ms
P99 延迟 112 ms 28 ms 21 ms
内存占用(空闲) 42 MB 38 MB 35 MB
关键发现:Sanic 在纯 JSON 响应场景下 RPS 最高,FastAPI 紧随其后且差距在 20% 以内。Flask 的同步模型在 100 并发下 P99 已超过 100ms,不适合低延迟场景。

3.3 异步 I/O 模型对比

三个框架的底层 I/O 模型决定了它们在高并发下的行为差异。下图展示了请求从接收到响应的完整生命周期。

三种框架请求处理流程对比 Flask (WSGI) Gunicorn 主进程 Worker 线程池 同步视图执行 返回响应 FastAPI (ASGI) Uvicorn 事件循环 async def 视图 Pydantic 校验 + 序列化 返回响应 Sanic (ASGI) Sanic 事件循环 async def 视图 手动序列化 (orjson) 返回响应 Flask 使用线程池处理请求,每个请求独占一个线程;FastAPI 和 Sanic 在事件循环中协程切换,无线程切换开销

3.4 序列化性能:Pydantic v2 的优势

评分接口的核心操作是接收请求参数 → 校验 → 调用模型 → 序列化结果。序列化环节在 FastAPI 中由 Pydantic v2 的 Rust 核心完成,相比纯 Python 序列化有 5-10 倍性能提升。

# FastAPI 示例:Pydantic 模型自动校验与序列化
from pydantic import BaseModel
from fastapi import FastAPI

app = FastAPI()

class ScoreRequest(BaseModel):
    user_id: str
    features: list[float]

class ScoreResponse(BaseModel):
    score: float
    risk_level: str

@app.post("/score", response_model=ScoreResponse)
async def predict(req: ScoreRequest):
    # 模拟模型推理
    score = sum(req.features) * 0.1
    level = "high" if score > 0.8 else "low"
    return ScoreResponse(score=score, risk_level=level)
注意:Sanic 不内置序列化引擎,若使用 Pydantic 需手动调用 model_dump() 或使用 orjson.dumps()。Flask 若使用 Marshmallow 序列化,在 1000+ RPS 场景下 CPU 开销会显著增加。

3.5 适用场景决策树

根据项目约束条件,按以下优先级选择框架:

  1. 需要自动 OpenAPI 文档 + 严格参数校验 → FastAPI(Pydantic 模型即文档)
  2. 极致吞吐量,纯 JSON 接口,无复杂校验 → Sanic(路由最快,内存最低)
  3. 已有 Flask 生态,迁移成本敏感,延迟要求不高 → Flask(配合 Gunicorn + gevent 可提升并发)
  4. 需要 WebSocket 实时推送评分结果 → FastAPI 或 Sanic(原生 ASGI 支持)
  5. 团队 Python 异步经验不足,但要求低延迟 → FastAPI(同步视图也可运行,逐步迁移)

3.6 生产部署配置参考

以下为三种框架在生产环境中的推荐启动方式:

# Flask + Gunicorn(4 worker,每个 worker 8 线程)
gunicorn -w 4 --threads 8 -b 0.0.0.0:8000 app:app

# FastAPI + Uvicorn(4 worker,每个 worker 1 事件循环)
uvicorn app:app --host 0.0.0.0 --port 8000 --workers 4

# Sanic(内置多 worker)
sanic app:app --host 0.0.0.0 --port 8000 --workers 4
低延迟调优建议:对于评分接口,建议将 worker 数设置为 CPU 核心数 × 2(FastAPI/Sanic)或 CPU 核心数 × 1(Flask 线程模式)。开启 keep-alive 连接复用可减少 TCP 握手开销。

3.7 本章小结

  • Flask 适合原型验证、内部工具、延迟不敏感的管理后台。
  • FastAPI 是评分接口的首选:Pydantic v2 校验 + ASGI 异步 + 自动文档,综合体验最佳。
  • Sanic 在纯 JSON 响应场景下性能最高,适合对延迟极度敏感的实时评分服务。
  • 选型时需同时考虑团队维护成本:FastAPI 的生态和文档成熟度最高,Sanic 社区较小。