菜鸟游戏网 - 游戏让生活变快乐! 全站导航 全站导航
AI工具安装教程 新手教程 进阶教程 辅助资源 AI提示词 热点资讯 技术资讯 产业资讯 内容生成 模型技术 AI信息库

已有账号?

您的位置 : 资讯 > 其他资讯 > FastAPI 性能优化:这五个配置让你的接口快三倍

FastAPI 性能优化:这五个配置让你的接口快三倍

来源:菜鸟下载 | 更新时间:2026-04-25

你的 FastAPI 慢得离谱,但你可能不知道 FastAPI 本身快吗?确实快。但那只是框架层面的潜力

你的 FastAPI 慢得离谱,但你可能不知道

FastAPI 本身快吗?确实快。但那只是框架层面的潜力。如果直接用默认配置一把梭,就好比买了辆跑车,却天天挂着一挡开——这能怪车慢吗?

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

今天分享五个关键配置,无需改动核心业务逻辑,也不必更换架构,调整后性能提升立竿见影。

配置一:Uvicorn Worker 数量——别再单进程裸奔了

这是最简单、也是收益最显著的一步。

FastAPI 默认使用 Uvicorn 单进程启动,这意味着即便你拥有一台 8 核服务器,实际上也只用到了 1 个核,其余 7 个都在闲置。

# 错误示范:单进程
# uvicorn main:app

# 正确做法:多 worker
# uvicorn main:app --workers 4

或者使用配置文件进行更精细的控制:

# gunicorn_conf.py
import multiprocessing

workers = multiprocessing.cpu_count() * 2 + 1  # 推荐公式
# 但注意,worker数通常不超过 CPU 核数的 2-4 倍,过多反而会因进程切换拖慢速度
worker_class = "uvicorn.workers.UvicornWorker"
bind = "0.0.0.0:8000"

启动命令相应调整为:

gunicorn main:app -c gunicorn_conf.py

需要特别注意的是,在多 worker 模式下,内存中的变量是不共享的。因此,切勿使用全局字典来存储状态。如果确实需要共享状态,引入 Redis 这类外部存储是更稳妥的方案。

配置二:response_model 不是摆设

你是否是这样写的接口?

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    user = await fetch_user_from_db(user_id)
    return user  # 直接返回 ORM 对象

问题在于,ORM 对象身上往往挂载着大量私有属性、延迟加载的关联数据以及内部方法。JSON 序列化时,框架需要遍历处理所有这些内容,速度自然快不起来。

正确的做法是加上 response_model

from pydantic import BaseModel

class UserResponse(BaseModel):
    id: int
    name: str
    email: str
    # 只定义需要暴露的字段

@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
    user = await fetch_user_from_db(user_id)
    return user

这样一来,FastAPI 将只序列化 response_model 中明确定义的字段,自动跳过 ORM 对象上所有无关的属性。当返回数据量较大时,序列化速度提升 40% 到 60% 是常有的事。此外,这个做法还顺便堵住了敏感字段意外泄漏的风险,可谓一举两得。

配置三:中间件顺序——你排错了,每个请求多花 50ms

FastAPI 的中间件遵循“洋葱模型”,后添加的中间件会先执行。但很多开发者忽略了顺序,随手添加:

# 错误示范:CORS 放在最外层,所有请求(包括静态资源)都要过一遍
app.add_middleware(GZipMiddleware)      # 第3个添加
app.add_middleware(CORSMiddleware, ...)  # 第2个添加
app.add_middleware(TimeLogMiddleware)    # 第1个添加

# 实际执行顺序:TimeLog → CORS → GZip → 路由

问题出在哪里?CORS 中间件会对所有请求(包括无需跨域的静态资源)进行检查,GZip 中间件也可能尝试压缩已经压缩过的响应。这些不必要的操作都在白白消耗 CPU 资源。

正确的顺序原则是:将最轻量的中间件放在最外层,最耗时的放在最内层。

# 推荐顺序:从外到内
app.add_middleware(TimeLogMiddleware)    # 日志记录,最轻量
app.add_middleware(GZipMiddleware)       # 响应压缩,中等开销
app.add_middleware(CORSMiddleware, ...)   # CORS 处理,相对最重

# 执行顺序:TimeLog → GZip → CORS → 路由

仅仅是这样一个小调整,每个请求节省几十毫秒轻而易举。如果日请求量达到百万级别,节省的总时间将非常可观。

配置四:数据库连接池——别每次请求都新建连接

这是新手最容易犯的错误,同时也是最容易修复的性能瓶颈。

# 错误示范:每次请求都新建连接
@app.get("/users")
async def list_users():
    conn = await asyncpg.connect("postgresql://...")
    users = await conn.fetch("SELECT * FROM users")
    await conn.close()
    return users

建立一次数据库连接的成本有多高?通常包括 TCP 三次握手、TLS 握手以及数据库鉴权,整个过程耗时可能在 50 到 100 毫秒之间。每个请求都重复这个过程,接口响应慢也就不足为奇了。

正确的做法是使用连接池:

from databases import Database

database = Database("postgresql://...", min_size=5, max_size=20)

@app.on_event("startup")
async def startup():
    await database.connect()

@app.on_event("shutdown")
async def shutdown():
    await database.disconnect()

@app.get("/users")
async def list_users():
    users = await database.fetch_all("SELECT * FROM users")
    return users

其中,min_size=5 表示应用启动时就预先建立好 5 个连接备用,max_size=20 则限定了连接池的最大容量。请求到来时直接从池中获取可用连接,用完后归还,完全避免了重复建立连接的开销。

如果使用 SQLAlchemy,原理相同:

from sqlalchemy.ext.asyncio import create_async_engine

engine = create_async_engine(
    "postgresql+asyncpg://...",
    pool_size=10,        # 连接池常驻连接数
    max_overflow=20,     # 高峰期允许额外创建的连接数
    pool_recycle=3600,   # 连接使用1小时后回收,防止数据库端主动断开
    pool_pre_ping=True,  # 从池中取出连接前先执行简单检测,确保连接存活
)

这里特别提一下 pool_pre_ping=True 这个参数,它堪称“救星配置”。数据库通常设有空闲连接超时断开机制,若代码持有一个已被服务端关闭的“死连接”去执行查询,会直接导致错误。开启 pre_ping 后,ORM 会在每次使用前自动检查连接有效性,并在失效时重新连接,极大地提升了稳定性。

配置五:缓存——能不查库就别查库

数据库查询再优化,其速度也难与内存读取相比。对于那些更新频率较低的数据,引入缓存是立竿见影的方案。

对于单机应用,可以使用 Python 内置的缓存:

from functools import lru_cache

@lru_cache(maxsize=128)
def get_config(key: str):
    """配置项基本不变,非常适合缓存"""
    return db.query(Config).filter_by(key=key).first()

如果需要支持过期时间,可以考虑更专业的库:

from cachetools import TTLCache

cache = TTLCache(maxsize=100, ttl=300)  # 缓存100条,每条存活5分钟

@app.get("/hot-articles")
async def hot_articles():
    if "hot_articles" in cache:
        return cache["hot_articles"]

    articles = await fetch_hot_articles_from_db()
    cache["hot_articles"] = articles
    return articles

如果是分布式部署,单机内存缓存就不够用了,此时需要引入 Redis 这类分布式缓存:

import aioredis
import json

redis = aioredis.from_url("redis://localhost")

@app.get("/hot-articles")
async def hot_articles():
    cached = await redis.get("hot_articles")
    if cached:
        return json.loads(cached)

    articles = await fetch_hot_articles_from_db()
    await redis.set("hot_articles", json.dumps(articles), ex=300)
    return articles

当然,缓存并非银弹。在写入频繁、读取较少的场景下,缓存收益甚微;而对于数据一致性要求极高的场景,则需要谨慎设计缓存策略。用错了缓存,带来的问题可能比不用更严重。

最后再说两句

以上五个配置,无需修改业务代码,也无需引入复杂的新架构,调整后通常能看到明显效果。如果按收益和优先级排序,大致如下:

  1. Uvicorn 多 Worker —— 直接提升应用吞吐量的基石。
  2. 数据库连接池 —— 直接降低每个请求的数据库访问延迟。
  3. response_model —— 加速序列化过程,同时增强接口安全性。
  4. 缓存 —— 适用于读多写少的场景,效果显著。
  5. 中间件顺序 —— 看似微小的优化,积少成多后收益可观。

千万别小看这些“配置细节”。很多时候接口性能不佳,问题并非出在框架本身,而恰恰在于这些基础配置没有被认真对待和优化。

菜鸟下载发布此文仅为传递信息,不代表菜鸟下载认同其观点或证实其描述。

展开
盗墓长生印荆轲破解版
盗墓长生印荆轲破解版
类型:动作射击 运营状态:公测 语言:简体中文
探险 独立游戏 经营
前往下载

相关文章

更多>>

热门游戏

更多>>