Python构建的FastAPI服务长时间闲置后卡住,按Ctrl+C才响应请求
问题根因
你遇到的卡住、终止服务才处理请求的现象,是以下几个代码问题共同导致的:
- 滥用async路由阻塞了事件循环:你将
/create路由定义为async类型,但函数内没有任何异步IO操作,同时后台运行的sklearn训练是CPU密集型同步任务,会直接占满主线程的事件循环,所有新请求都会被挂起排队,不会被处理。按下Ctrl+C时会触发中断解除阻塞,队列里的积压请求才会被批量执行,因此会出现终止服务时才打印之前请求日志的情况。 - 代码存在基础错误:
- 入口判断写为
if __name__ = "__main__",单等号是赋值操作,正确应为双等号== - 启动uvicorn时没有传入app实例,会导致服务启动异常
/create路由的tasks参数没有定义Pydantic请求模型,FastAPI无法解析请求体,收到请求时会抛出异常,进一步加重阻塞
- 入口判断写为
修复方案
1. 调整路由定义
没有异步IO操作的路由不要加async修饰,FastAPI会自动将普通def定义的路由放到独立线程池运行,不会阻塞主线程事件循环,完整修复后的代码如下:
from fastapi import FastAPI, BackgroundTasks from sklearn.linear_model import LinearRegression import uvicorn from pydantic import BaseModel from typing import List app = FastAPI() # 补全请求体模型定义 class TrainingTask(BaseModel): train_data: List[List[float]] train_label: List[float] def train_model(tasks: TrainingTask): x = tasks.train_data y = tasks.train_label model = LinearRegression() model.fit(x, y) score = model.score(x, y) print("Score:", score) # 去掉async,用普通def定义路由,指定tasks参数类型 @app.post("/create") def train(tasks: TrainingTask, background_tasks: BackgroundTasks): background_tasks.add_task(train_model, tasks) return {"Received training request": True} # 修复入口语法错误,传入app实例 if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=5000)
2. 可选优化
如果训练任务耗时较长,建议启动uvicorn时开启多worker,避免单个worker被长时间占用导致其他请求无法响应,启动命令如下:
uvicorn main:app --host 0.0.0.0 --port 5000 --workers 4
如果训练任务量级很大,建议引入专门的分布式任务队列处理后台计算,不要占用API服务的运行资源。
内容的提问来源于stack exchange,提问作者林彥良
相关产品推荐
相关产品推荐

