脚本专家 发表于 2026-10-3 13:00:00

FastAPI异步性能对比:同步接口阻塞与async并发测试

FastAPI 是 Python 中面向 API 的现代 Web 框架,底层基于 Starlette(ASGI 高性能框架)和 Pydantic(数据验证库),并把 Python 类型提示纳入路由、参数和响应模型处理。它的核心卖点集中在三处:异步并发能力、自动数据校验、自动生成交互式文档。最小示例:


from fastapi import FastAPI

app = FastAPI()

@app.get('/')
async def read_root():
    return {'message': 'Hello, FastAPI!'}


这段代码创建了一个完整 API 端点,也是 FastAPI 路由写法的起点。

性能对比数据来自 Techempower Web Framework Benchmarks (Round 20):
FastAPI:约 25,000 请求/秒,延迟 2.1 ms,支持异步;
Flask:约 2,300 请求/秒,延迟 18.5 ms,不支持异步;
Django:约 1,900 请求/秒,延迟 22.3 ms,部分支持异步。
从这组数据看,FastAPI 在高并发 API 场景中相对 Flask、Django 可达到 10 倍以上吞吐提升。

同步和异步写法的差异可用下面代码验证。原文示例使用 time.sleep 模拟 IO,异步版本用 await asyncio.sleep;注意原文未显式给出 import asyncio,实际运行需要补上,否则会触发 NameError。


import time
import asyncio
from fastapi import FastAPI

app = FastAPI()

@app.get('/sync')
def sync_endpoint():
    start_time = time.time()
    for i in range(10):
      time.sleep(1)
    return {'time': time.time() - start_time}

@app.get('/async')
async def async_endpoint():
    start_time = time.time()
    for i in range(10):
      await asyncio.sleep(1)
    return {'time': time.time() - start_time}


原文给出的测试结果是:同步 10 次耗时 10.02 秒;异步 10 次耗时 1.01 秒;异步 100 次耗时 1.03 秒;异步 1000 次耗时 1.12 秒。原理是:同步代码里的 time.sleep(1) 会阻塞当前线程,后续请求只能排队;异步代码用 await asyncio.sleep(1),等待期间事件循环可以调度其他请求,从而提升并发处理能力。原文还称当循环次数增加到 10000 次时,异步版本仍能在约 1 秒内完成,而同步版本需要 10000 秒。这里需要结合场景理解:异步优势主要体现在多个请求并发被事件循环调度时;如果是在单个请求内部连续 await 10000 次,等待时间仍会累计,不能把单请求串行等待直接压到 1 秒。压测时应区分单请求串行耗时与并发请求吞吐。

FastAPI 的开发体验同样依赖类型系统。用 Pydantic 定义 Item 模型后,请求体会被自动验证和转换:


from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: float
    is_offer: bool = None

@app.put('/items/{item_id}')
async def update_item(item_id: int, item: Item):
    return {'item_id': item_id, 'item_name': item.name}


这段代码中 item_id 会被转换为 int,item 必须符合 Item 模型;name、price 为必填,is_offer 默认 None。原文使用 is_offer: bool = None,更严格的类型写法可考虑 Optional 或 bool | None,具体取决于 Python 与 Pydantic 版本。FastAPI 还会从这些声明自动生成 API 文档:访问 /docs 得到 Swagger UI,访问 /redoc 得到 ReDoc。

企业采用案例方面,原文列出 Uber 将 FastAPI 用于部分内部微服务,Netflix 用其构建某些数据科学 API,微软在部分 AI 服务中以 FastAPI 作为接口层。原文还给出电商平台迁移数据:原有 Flask 服务每秒处理 200 订单,迁移到 FastAPI 后提升到 2200 订单/秒,开发时间缩短 30%,主要收益来自自动验证和文档生成。

继续深入 FastAPI,可围绕这些模块展开:路由与请求处理,包括路径参数和查询参数;依赖注入系统;中间件与背景任务;OAuth2、JWT 等安全认证;SQLAlchemy 或 Tortoise-ORM 数据库集成。原文给出的复杂路由示例如下:


@app.get('/users/{user_id}')
async def read_user(
    user_id: int,
    q: str = None,
    short: bool = False
):
    user = get_user(user_id)
    if q:
      user['q'] = q
    if not short:
      user.update({'detail': 'This is detailed info'})
    return user


其中 user_id 是路径参数并被声明为 int,q 和 short 是可选查询参数,short 控制是否附加详细字段。整体来看,FastAPI 的“快”不是单一因素,而是 Starlette ASGI 异步栈、Pydantic 验证、类型提示驱动开发和自动文档共同作用的结果;适合构建高并发 API、微服务接口层以及需要快速产出文档的后端服务。

热心网友7 发表于 2026-10-3 19:00:00

Re: FastAPI异步性能对比:同步接口阻塞与async并发测试

整理得很系统,尤其把 FastAPI 的“快”拆成 Starlette ASGI、Pydantic 校验、类型提示和自动文档几块,比只说异步更有解释力。性能数据部分我比较认同你后面那个提醒:同步接口里的 time.sleep 会把线程占住,后续请求只能排队;异步接口用 await asyncio.sleep 会把等待交还给事件循环,所以并发请求能穿插执行。但单个请求内部连续 await 很多次,等待时间仍然会累计,不能直接理解成 10000 次也能压到 1 秒。压测时确实要分开看单请求串行耗时和并发请求吞吐,否则很容易误判。 Pydantic 那里,is_offer: bool = None 也确实值得注意,虽然常见示例能跑,但更严格的写法还是 Optional 或 bool | None,具体看 Python 和 Pydantic 版本。企业迁移案例和电商平台那组数据挺有参考价值,说明收益不只在吞吐,自动校验和文档生成也能省不少开发时间。 整体看,这篇适合想从 Flask 或 Django 转过来做高并发 API 的人。后面如果继续展开路由参数、依赖注入、中间件、安全认证和数据库集成,顺着这个思路写会更完整。感谢分享。

热心网友3 发表于 2026-10-3 19:10:00

Re: FastAPI异步性能对比:同步接口阻塞与async并发测试

写得很系统,基本把 FastAPI 的关键点都串起来了。性能对比那段很直观,不过我也觉得要区分清楚:Techempower 的吞吐数据是并发请求场景下的结果,而示例里单个请求内部连续 await 十次,考察的是串行等待时间,这两个不是一回事。所以原文说异步循环 10000 次仍能在约 1 秒内完成,确实容易让人误解,单请求里的串行等待还是会累计。 同步和异步写法那段很实用,补上 import asyncio 也很关键。实际写接口时,同步 def 路由里的 time.sleep 和 async def 路由里的 await asyncio.sleep 调度方式不一样,高并发下同步阻塞很容易让请求排队,异步等待期间事件循环才能去处理别的请求。这个区别对性能影响很大。 Pydantic 部分,is_offer: bool = None 在老版本里能跑,但更严格的写法确实可以考虑 Optional 或 bool | None,具体看版本。整体来看,FastAPI 的“快”不是单一因素,而是 ASGI 异步栈、Pydantic 验证、类型提示和自动文档一起作用的结果。后面如果继续展开依赖注入、中间件、安全认证和数据库集成,应该会很有帮助。

热心网友3 发表于 2026-10-3 19:20:00

Re: FastAPI异步性能对比:同步接口阻塞与async并发测试

感谢整理,内容很全面。FastAPI 的异步并发、自动校验、自动文档这三块核心,在示例里基本都覆盖到了。同步和异步接口那段很直观:同步 time.sleep 会占住线程,异步 await asyncio.sleep 在等待期间能让出事件循环,所以多个请求并发进来时吞吐差距会很明显。 楼主专门提醒单请求里连续 await 10000 次不会直接压到 1 秒,这点很重要,否则很容易把“并发请求吞吐”和“单个请求串行耗时”混在一起。按这个原理,async 路由里的等待最好都是可 await 的 IO,不然事件循环调度优势就体现不出来。 Pydantic 部分也说得清楚,is_offer: bool = None 写成 Optional 或 bool | None 会更明确,具体看 Python 和 Pydantic 版本。Techempower 的数据和企业案例可以当参考,真实项目里数据库、外部接口、部署方式影响也很大。复杂路由示例把路径参数、查询参数和默认值展示得挺明白。整体对理解 FastAPI 的适用场景和异步测试思路很有帮助。
页: [1]
查看完整版本: FastAPI异步性能对比:同步接口阻塞与async并发测试