摘要:本文系统讲解 FastAPI 中lifespan的用法,介绍其作为异步上下文管理器在应用启动和关闭时管理资源生命周期的机制,并通过数据库连接池、机器学习模型加载、app.state共享资源等实战示例,展示如何编写清晰的启动与清理逻辑,最后对比已废弃的on_event,说明lifespan是官方推荐的现代方案。
1. 引言
在 FastAPI 中,lifespan是管理应用启动和关闭时资源生命周期的重要机制。它取代了早期版本中已废弃的on_event方式,提供了更清晰、更可控的异步上下文管理方案。本文将从基本概念、实际用法到常见场景,系统讲解 FastAPI 中lifespan的用法。
2. 什么是 lifespan
lifespan是 FastAPI 提供的一个异步上下文管理器,用于在应用启动时执行初始化逻辑(如建立数据库连接、加载模型),并在应用关闭时执行清理逻辑(如关闭连接、释放资源)。它通过asynccontextmanager实现,代码结构清晰,异常处理也更可靠。
3. 基本用法
使用lifespan需要从contextlib导入asynccontextmanager,然后定义一个异步生成器函数,在yield之前是启动逻辑,yield之后是关闭逻辑。最后将lifespan传给FastAPI实例。
from contextlib import asynccontextmanager from fastapi import FastAPI @asynccontextmanager async def lifespan(app: FastAPI): # 启动时执行 print("应用启动中...") yield # 关闭时执行 print("应用关闭中...") app = FastAPI(lifespan=lifespan)4. 在 lifespan 中管理数据库连接
最常见的场景是在应用启动时建立数据库连接池,并在关闭时释放。下面以 SQLAlchemy 异步引擎为例。
from contextlib import asynccontextmanager from fastapi import FastAPI from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker DATABASE_URL = "sqlite+aiosqlite:///./test.db" engine = None SessionLocal = None @asynccontextmanager async def lifespan(app: FastAPI): global engine, SessionLocal engine = create_async_engine(DATABASE_URL) SessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) print("数据库连接池已创建") yield await engine.dispose() print("数据库连接池已释放") app = FastAPI(lifespan=lifespan)5. 在 lifespan 中加载机器学习模型
对于机器学习服务,通常需要在启动时加载模型,避免每次请求都重复加载。可以将模型实例存储在应用状态中,供路由处理函数使用。
from contextlib import asynccontextmanager from fastapi import FastAPI model = None @asynccontextmanager async def lifespan(app: FastAPI): global model # 模拟加载模型 model = {"name": "my_model", "version": "1.0"} print("模型加载完成") yield model = None print("模型已释放") app = FastAPI(lifespan=lifespan) @app.get("/predict") async def predict(): if model is None: return {"error": "模型未加载"} return {"model": model["name"], "version": model["version"]}6. 使用 app.state 共享资源
更推荐的做法是将资源挂载到app.state上,这样在路由中可以通过request.app.state访问,避免使用全局变量。
from contextlib import asynccontextmanager from fastapi import FastAPI, Request @asynccontextmanager async def lifespan(app: FastAPI): # 启动时初始化 app.state.db_pool = {"size": 10, "status": "ready"} app.state.model = {"name": "bert", "version": "2.0"} print("资源初始化完成") yield # 关闭时清理 app.state.db_pool = None app.state.model = None print("资源清理完成") app = FastAPI(lifespan=lifespan) @app.get("/status") async def status(request: Request): return { "db": request.app.state.db_pool, "model": request.app.state.model }7. lifespan 与 on_event 的对比
早期 FastAPI 使用on_event("startup")和on_event("shutdown")处理启动和关闭逻辑,但这种方式存在一些问题:事件处理函数之间没有明确的执行顺序保证,且难以共享状态。而lifespan通过单个异步上下文管理器统一管理,执行顺序明确,代码更简洁,也更符合 Python 的异步编程习惯。
| 对比项 | on_event | lifespan |
|---|---|---|
| 执行顺序 | 不保证 | 明确(yield 前后) |
| 状态共享 | 依赖全局变量 | 可通过 app.state |
| 异常处理 | 较繁琐 | 上下文管理器自动处理 |
| 推荐程度 | 已废弃 | 官方推荐 |
8. 总结
lifespan是 FastAPI 管理应用生命周期的推荐方式,适用于数据库连接、模型加载、缓存初始化等场景。通过asynccontextmanager定义启动和关闭逻辑,配合app.state共享资源,可以让代码更清晰、更易维护。建议新项目直接使用lifespan,避免使用已废弃的on_event。