
ContextVar 的值在 asyncio 任务(如 FastAPI 请求处理协程)结束时由 Python 运行时自动清理,无需显式调用 reset();其生命周期与任务上下文严格绑定,确保并发请求间上下文隔离且无内存泄漏。
contextvar 的值在 asyncio 任务(如 fastapi 请求处理协程)结束时由 python 运行时自动清理,无需显式调用 `reset()`;其生命周期与任务上下文严格绑定,确保并发请求间上下文隔离且无内存泄漏。
在异步 Web 框架(如 FastAPI)中,ContextVar 是实现请求级上下文隔离的核心机制。你示例中将 AsyncSession 存入 session_context = ContextVar("session"),看似未调用 session_context.reset(token),但实际完全安全——Python 的 asyncio 运行时会在每个独立任务(task)退出时自动销毁其所属的 context,包括所有绑定的 ContextVar 值。
这意味着:
- 每次 HTTP 请求触发的
main()协程运行在一个全新的、隔离的 context 中; - 即使你在协程内调用
session_context.set(session),该绑定仅对该请求生命周期有效; - 当
main()协程执行完毕(返回响应后),整个 context 被垃圾回收,session_context.get()在后续新请求中会抛出LookupError(除非重新 set),旧 session 对象也会随 context 一并被释放。
✅ 正确行为验证(精简版):
import asyncio
import contextvars
ctx = contextvars.ContextVar("test", default="unset")
async def req_handler(n):
ctx.set(f"req-{n}")
print(f"[{n}] set → {ctx.get()}")
await asyncio.sleep(0.01)
print(f"[{n}] get → {ctx.get()}")
async def main():
await asyncio.gather(req_handler(1), req_handler(2))
# 此处已不在任一请求 context 中
print(f"Outside: {ctx.get()}") # 输出: unset(默认值)
asyncio.run(main())输出:
[1] set → req-1 [2] set → req-2 [1] get → req-1 [2] get → req-2 Outside: unset
⚠️ 注意事项:
-
不要在后台任务(如
BackgroundTasks)中复用主请求的 ContextVar:check_connections_statuses在新 task 中执行,它拥有独立 context,session_context.get()可能失败或取到意外值(除非显式copy_context()并传递); -
避免跨 await 边界长期持有 session 引用:你代码中
await session.close()后仍保留 session 对象在 context 中,虽不泄漏连接(因已 close),但建议在 request 结束前主动reset()提升可读性(非必须,但更规范); -
ContextVar 不替代依赖注入:对于 SQLAlchemy Session,推荐使用 FastAPI 的
Depends+yield依赖(支持自动 cleanup),而非手动 ContextVar 管理,更符合框架约定且更健壮。
总结:Python 的 contextvars 设计即为“按任务自动生命周期管理”,你无需也不应手动 reset —— 它是语言原生保障的并发安全特性。放心使用,专注业务逻辑即可。


















