Lazy loaded image
产品真经
FastAPI性能优化:10个实用技巧让你的应用飞起来
字数 2094阅读时长 6 分钟
2025-12-14
2025-12-14
type
status
date
slug
summary
tags
category
icon
password
FastAPI 以其出色的性能和开发体验而闻名,但要真正发挥其潜力,你需要掌握一些关键的优化技巧。本文将分享 10 个实用的性能优化建议,涵盖从异步编程最佳实践到测试框架选择的方方面面。无论你是 FastAPI 新手还是经验丰富的开发者,这些技巧都将帮助你构建更快、更可靠的应用程序。
 
1. 安装 uvloop 和 httptools
默认情况下,Uvicorn 不包含 uvloop 和 httptools,这两个库的性能比默认的 asyncio 事件循环和 HTTP 解析器更好。你可以使用以下命令安装它们:
如果在你的环境中安装了 Uvicorn,它会自动使用它们。
page icon
uvloop 无法在 Windows 上安装。如果你在本地使用 Windows,但在生产环境中使用 Linux,你可以使用环境标记来避免在 Windows 上安装 uvloop,例如 uvloop; sys_platform != 'win32' 。
 
2. 谨慎使用非异步函数
在 FastAPI 中使用非异步函数会产生性能损耗。因此,应始终优先使用异步函数。性能损耗来自于 FastAPI 将调用 run_in_threadpool,它会使用线程池运行该函数。
page icon
在内部,run_in_threadpool 会使用 anyio.to_thread.run_sync 在线程池中运行该函数。
page icon
线程池中只有 40 个线程可用。如果使用完所有线程,你的应用程序将被阻塞。
要改变可用的线程数,可以使用以下代码:
你可以在 AnyIO 的文档中阅读更多信息。
 
3. 在 WebSocket 上使用 async for 而不是 while True
你在互联网上找到的大多数示例都使用 while True 来读取 WebSocket 中的消息。
我认为使用这种更不优雅的写法主要是因为 Starlette 文档长期没有展示 async for 的写法。
与使用 while True 相比:
你可以使用 async for 记号:
你可以在 Starlette 文档中阅读更多相关内容。
 
4. 忽略 WebSocketDisconnect 异常
如果你使用 while True 记号,你需要捕获 WebSocketDisconnectasync for 记号会自动为你捕获它。
如果你需要在 WebSocket 断开连接时释放资源,你可以使用该异常来实现。
如果您使用的是较旧的 FastAPI 版本,只有 receive 方法会抛出 WebSocketDisconnect 异常。send 方法不会抛出它。在最新版本中,所有方法都会抛出它。在这种情况下,您需要将 send 方法添加到 try 块中。
 
5. 使用 HTTPX 的 AsyncClient 而不是 TestClient
由于您在应用程序中使用 async 函数,使用 HTTPX 的 AsyncClient 会更容易 而不是 Starlette 的 TestClient
如果你正在使用生命周期事件(on_startupon_shutdown 或 lifespan 参数),你可以使用 asgi-lifespan 包来运行这些事件。
page icon
考虑通过 GitHub Sponsors 支持 asgi-lifespanFlorimond Manca 的创建者。
 
6. 使用 Lifespan State 而不是 app.state
不久前,FastAPI 开始支持 lifespan state,它定义了一种标准方式来管理需要在启动时创建并在请求-响应周期中使用的对象。
不再推荐使用 app.state。你应该改用 lifespan state
使用 app.state,你可以这样做:
使用生命周期状态,你可以这样做:
 
7. 启用 AsyncIO 调试模式
如果你想找到阻塞事件循环的端点,可以启用 AsyncIO 调试模式。
启用后,当任务执行耗时超过 100ms 时,Python 会打印警告消息。
使用 PYTHONASYNCIODEBUG=1 python main.py 运行以下代码:
如果你调用该端点,你会看到以下消息:
你可以在 官方文档 中了解更多信息。
 
8. 实现纯 ASGI 中间件而不是 BaseHTTPMiddleware
BaseHTTPMiddleware 是在 FastAPI 中创建中间件的最简单方式。
注意
@app.middleware("http") 装饰器是 BaseHTTPMiddleware 的包装器。
BaseHTTPMiddleware 曾存在一些问题,但在最新版本中大多数问题都已修复。不过,使用它仍然会带来性能损耗。
为了避免性能损耗,你可以实现一个纯 ASGI 中间件 。缺点是实现起来更加复杂。
检查 Starlette 的文档来了解如何实现纯 ASGI 中间件 
 
9. 你的依赖项可能在线程上运行
如果函数是非异步的,并且你将其用作依赖项,它将在线程中运行。
在下面的示例中,http_client 函数将在一个线程中运行:
要在事件循环中运行,你需要将函数设为异步:
 
你可以使用 python main.py 运行以下代码:
如果你调用该端点,你会看到以下消息:
将 def http_client 替换为 async def http_client 并重新运行应用程序。你将看不到 Threads in use: 1 这条消息,因为该函数在事件循环中运行。
 
 
10. 使用 pytest.mark.anyio 而不是 pytest.mark.asyncio
你已经安装了 anyio,因为它是 Starlette 的依赖项。这意味着,你可以使用 pytest.mark.anyio 而不是 pytest.mark.asyncio
默认情况下,anyio 会将每个标记的测试运行两次,一次使用 trio,另一次使用 asyncio。如果你正在测试一个应用程序而不是一个包,你可能想通过使用其中一个来限制这个行为:
 
 
上一篇
虚拟化容器化的区别以及REST API等基本概念
下一篇
Fast Api最佳实践指南