You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI中SQLAlchemy同步会话性能远超异步的原因探究

异步FastAPI+SQLAlchemy性能远低于同步版本的原因分析与优化建议

问题背景

开发了两个FastAPI应用版本:

  • 异步版本:采用SQLAlchemy异步数据库连接
  • 同步版本:采用SQLAlchemy同步连接

性能测试结果差异巨大:

  • 异步版本:1000次请求耗时约500秒
  • 同步版本:1000次请求耗时0.72秒

环境配置:

  • FastAPI:0.95.1
  • SQLAlchemy:2.0.19
  • 数据库:SQLite
  • PyNest:0.1.0

核心原因分析

1. SQLite的异步本质局限性

SQLite是单文件、单线程数据库,即使使用aiosqlite异步驱动,底层依然无法实现真正的并行IO操作——SQLite的写操作依赖全局锁,读操作在写锁存在时也会阻塞。异步版本的"异步"仅将阻塞操作转移到事件循环线程,没有真正提升并行处理能力,反而因异步框架的调度开销,比同步版本更慢。

2. 同步版本的会话复用与逻辑差异

同步版本的TransactionService使用@lru_cache()装饰器,意味着整个应用生命周期内仅初始化一次实例,对应的数据库会话会被复用,省去了频繁创建、销毁会话的开销;而异步版本的get_db()每次请求都会创建新的异步会话,请求结束后关闭,这部分额外开销被1000次请求放大。

另外,同步版本的get_transactions()仅返回first()数据,而异步版本返回all()——若数据库中数据量较大,这会进一步加剧性能差异。

3. 异步框架的冗余调度开销

异步事件循环需要处理协程切换、调度,对于SQLite这种本身无法并行的场景,这些额外调度完全是冗余的,直接拖慢了整体性能。

异步版本优化建议

1. 更换支持真正异步的数据库

若要发挥异步框架优势,建议将SQLite替换为PostgreSQL、MySQL等支持真正异步IO的数据库,配合asyncpg、aiomysql等异步驱动,才能让异步连接的并行能力得到发挥。

2. 优化异步会话管理

避免每次请求创建新会话,通过连接池复用会话:

class Config:
    def __init__(self):
        # 配置连接池参数,控制会话复用
        self.engine = create_async_engine(
            "sqlite+aiosqlite:///finance.db",
            connect_args={"check_same_thread": False},
            pool_size=10,
            max_overflow=20
        )
        self.SessionLocal = async_sessionmaker(self.engine)
        self.Base = Base

    async def get_db(self):
        async with self.SessionLocal() as session:
            yield session

使用async with管理会话,确保会话正确复用,减少创建/销毁的开销。

3. 对齐测试逻辑与数据返回

  • 将异步版本接口的query.scalars().all()改为返回first()(与同步版本逻辑对齐),或改为分页返回,减少数据序列化和传输的开销。
  • 调整测试脚本的并发数,1000个同时请求会导致SQLite锁竞争加剧,可降低并发数或采用逐步加压的测试方式。

4. 评估异步必要性

若坚持使用SQLite,同步版本的性能已足够,无需强行使用异步。异步框架更适合IO密集型、高并发且数据库支持异步的场景。


内容的提问来源于stack exchange,提问作者ItayDar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 17:02:40