FastAPI中async/await引发请求阻塞的解决方案咨询
解决FastAPI异步接口阻塞请求的变通策略
核心前提
异步接口出现阻塞,本质不是async/await语法本身的问题,大概率是代码中混入了同步阻塞操作(比如同步IO、CPU密集计算),或是AsyncIOMotorClient的使用方式有误,以下是具体的解决思路:
具体解决方案
1. 把同步阻塞逻辑隔离到线程池
如果你的异步函数里存在同步代码(比如旧的同步SDK、复杂计算),用asyncio.to_thread将其丢到线程池执行,避免阻塞主事件循环:
from fastapi import APIRouter import asyncio someRequestsApis = APIRouter() # 假设这是你无法替换的同步阻塞逻辑 def sync_blocking_task(): return list(some_sync_db_operation()) @someRequestsApis.get("/something/") async def getThings(): # 同步任务转线程池执行 sync_result = await asyncio.to_thread(sync_blocking_task) # 正常执行Motor异步查询 db_result = await things.find().to_list(length=100) return {"sync_data": sync_result, "db_data": db_result}
2. 规范AsyncIOMotorClient的使用
- 全局仅初始化一次客户端,禁止在请求函数内重复创建:
# 在项目入口文件(如main.py)全局初始化 from motor.motor_asyncio import AsyncIOMotorClient client = AsyncIOMotorClient("mongodb://localhost:27017") db = client["your_database"] things = db["your_collection"] - 查询时显式指定
length参数(比如to_list(length=200)),避免一次性拉取过量数据导致内存占用过高。
3. 替换高性能事件循环
默认的事件循环性能有限,安装uvloop替换后能提升异步任务处理效率:
pip install uvloop
在启动文件中配置:
import uvloop import asyncio asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) if __name__ == "__main__": import uvicorn uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
4. 后台任务的异步适配
后台任务如果包含阻塞逻辑,同样要异步化或丢到线程池,不能直接使用同步函数:
from fastapi import APIRouter, BackgroundTasks someRequestsApis = APIRouter() async def async_background_job(): await things.update_one({"_id": 1}, {"$set": {"status": "completed"}}) # 同步逻辑用to_thread包裹 await asyncio.to_thread(some_sync_background_task) @someRequestsApis.get("/start-background/") async def start_task(background_tasks: BackgroundTasks): background_tasks.add_task(async_background_job) return {"message": "后台任务已启动"}
内容的提问来源于stack exchange,提问作者DUMBA
相关产品推荐
相关产品推荐

