FastAPI 生命周期事件详解:优雅管理应用启动与关闭
什么是生命周期事件
在 FastAPI 应用中,生命周期事件指的是应用启动前和关闭时需要执行的特定逻辑。这些逻辑通常包括:
- 应用启动前:初始化数据库连接池、加载机器学习模型等耗时操作
- 应用关闭时:释放资源、保存状态、关闭连接等清理工作
为什么需要生命周期事件
考虑以下典型场景:
- 机器学习模型加载:一个大型模型加载可能需要数秒甚至更长时间,如果在每次请求时都加载,性能将无法接受
- 数据库连接池:应用启动时建立连接池,所有请求共享,而不是每个请求都新建连接
- 资源释放:应用关闭时需要确保GPU内存、文件句柄等资源被正确释放
现代推荐方案:lifespan 参数
FastAPI 推荐使用 lifespan
参数来管理生命周期,这是一个异步上下文管理器模式。
基础示例
from contextlib import asynccontextmanager
from fastapi import FastAPI
# 模拟机器学习模型
fake_database = {}
@asynccontextmanager
async def lifespan(app: FastAPI):
# 启动时加载模型
fake_database["model"] = lambda x: x * 2 # 简单示例模型
yield
# 关闭时清理资源
fake_database.clear()
app = FastAPI(lifespan=lifespan)
@app.get("/predict")
async def predict(x: int):
return {"result": fake_database["model"](x)}
关键点解析
- @asynccontextmanager:将普通函数转换为异步上下文管理器
- yield 语句:分隔启动逻辑和关闭逻辑
- 资源共享:
fake_database
被所有请求共享,避免重复加载
传统方案(已弃用)
虽然仍可使用,但不推荐在新项目中使用以下方式:
启动事件
app = FastAPI()
@app.on_event("startup")
async def startup_event():
app.state.model = lambda x: x * 2
关闭事件
@app.on_event("shutdown")
def shutdown_event():
with open("log.txt", mode="a") as log:
log.write("Application shutdown")
为什么不推荐
- 启动和关闭逻辑分离,难以共享状态
- 不如
lifespan
方案直观和结构化 - 未来版本可能会移除
实际开发建议
- 资源初始化:将数据库连接池、模型加载等耗时操作放在
yield
前 - 资源释放:文件关闭、连接池清理等放在
yield
后 - 错误处理:考虑在
lifespan
中添加异常处理逻辑 - 测试考虑:生命周期事件不会在简单测试中触发,需要专门测试
高级用法
对于复杂场景,可以在 lifespan
中管理多个资源:
@asynccontextmanager
async def complex_lifespan(app: FastAPI):
# 初始化多个资源
db_pool = await create_db_pool()
ml_model = load_ml_model()
cache = setup_redis()
# 将资源存入app状态
app.state.db = db_pool
app.state.model = ml_model
app.state.cache = cache
yield
# 清理资源
await db_pool.close()
ml_model.unload()
await cache.disconnect()
注意事项
- 子应用限制:生命周期事件不会在挂载的子应用中触发
- 异步兼容:确保资源管理与FastAPI的异步特性兼容
- 执行顺序:多个
lifespan
管理器的执行顺序可能影响初始化
通过合理使用生命周期事件,可以显著提升FastAPI应用的性能和可靠性,特别是在资源密集型场景下。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考