fastapi项目细节和启动顺序

要搞清楚 FastAPI 项目启动的执行逻辑,需要先明确 “项目启动流程”“main 函数角色”“lifespan 作用”“导入语句执行时机” 这几个核心点的关系,下面逐一拆解:

一、FastAPI 项目启动:先执行 “导入语句”,再执行 “main 函数”,最后触发 “lifespan”

FastAPI 项目的启动并非单一入口执行,而是遵循 “Python 解释器执行顺序”+“FastAPI 框架初始化逻辑” 的组合流程,整体顺序如下:

1. 第一步:执行所有 “导入语句”(最早发生)

当你通过命令(如 uvicorn main:app --reload)启动项目时,Python 解释器会先加载所有被引用的模块 ——导入语句(import)的执行时机,是 “模块被加载时”,早于任何函数(包括 main)的调用

FastAPI 项目的启动并非单一入口执行,而是遵循 “Python 解释器执行顺序”+“FastAPI 框架初始化逻辑” 的组合流程,整体顺序如下:

1. 第一步:执行所有 “导入语句”(最早发生)

当你通过命令(如 uvicorn main:app --reload)启动项目时,Python 解释器会先加载所有被引用的模块 ——导入语句(import)的执行时机,是 “模块被加载时”,早于任何函数(包括 main)的调用

举个典型的项目结构例子:

your_project/
├── main.py       # 入口文件,有 app = FastAPI()、main 函数
└── config.py     # 配置文件,有 AGENT_CONFIGS、预加载文件逻辑

如果 main.py 中有这样的代码:

# main.py
# 1. 导入语句:此时会立即执行 config.py 中的所有代码
import config  
from fastapi import FastAPI# 2. 初始化 FastAPI 实例:此时执行(早于 main 函数)
app = FastAPI()# 3. 定义 main 函数(启动命令中可能不直接调用,除非主动执行)
def main():print("执行 main 函数")# 4. 定义 lifespan(FastAPI 1.0+ 推荐的生命周期钩子)
@app.lifespan("startup")
async def startup_event():print("执行 startup 生命周期事件")

当你运行 uvicorn main:app 时,第一步就是执行 导入语句 import config—— 这会触发 config.py 中的所有代码(包括初始化函数、类、变量如 AGENT_CONFIGS” 等逻辑),且这个过程在 app 实例化、main 函数调用、lifespan 触发之前。

2. 第二步:FastAPI 初始化 app 实例(无 main 时也会执行)

导入完成后,Python 解释器会执行 main.py 中 “顶层代码”(即不在函数 / 类内部的代码),比如 定义常量、全局变量等。如app = FastAPI()—— 这一步会初始化 FastAPI 应用的核心对象(路由、中间件、生命周期等),但不会启动服务。

注意:main 函数并非 FastAPI 启动的 “必需入口”

  • 如果你用 uvicorn main:app 启动,uvicorn 会直接加载 main.py 中的 app 实例,不会主动调用 main 函数(除非你在 main.py 中主动加 if __name__ == "__main__": main());
  • 只有当你用 “自定义启动逻辑”(比如用 FastAPI.run() 或 uvicorn.run() 在 main 函数中启动)时,main 函数才会被执行,例如:
    # 自定义 main 函数启动服务(非必需,但常见于需要预处理的场景)
    def main():# 启动前的预处理(如检查配置)print("启动前检查配置...")# 调用 uvicorn 启动服务uvicorn.run("main:app", host="0.0.0.0", port=8000)if __name__ == "__main__":main()  # 此时运行 `python main.py` 会执行 main 函数
    3. 第三步:触发 lifespan 生命周期事件(服务启动 / 关闭时执行)

    当 uvicorn 成功加载 app 实例并准备启动服务时,会触发 FastAPI 的 lifespan 生命周期钩子—— 这是 FastAPI 框架层面提供的 “服务启动 / 关闭时执行代码” 的标准方式,优先级低于 “导入语句” 和 “顶层代码”,但高于 “用户请求处理”。

    lifespan 的执行时机:

  • startup 事件:服务启动成功后、开始接收用户请求前执行(比如初始化数据库连接、加载全局缓存);
  • shutdown 事件:服务停止前、断开所有用户连接后执行(比如关闭数据库连接、释放资源)。

例如你在 main.py 中定义的 startup_event,会在 app 初始化完成、uvicorn 准备好接收请求时执行,晚于 import config 和 app = FastAPI(),早于第一个用户请求。


步骤如下:

执行步骤操作内容执行时机是否主动调用
1执行 import config 等导入语句Python 加载模块时(最早)自动(解释器触发)
2执行 app = FastAPI()main.py 顶层代码执行时(导入后)自动(解释器触发)
3执行 main() 函数(若有)运行 python main.py 且触发 if __name__ == "__main__" 时手动(需代码调用)
4执行 startup 生命周期事件服务启动成功后、接收请求前自动(FastAPI 触发)
5处理用户请求服务启动后、startup 事件执行完成后被动(用户触发)
6执行 shutdown 生命周期事件服务停止前、断开用户连接后自动(FastAPI 触发)

三、实际开发中的注意事项

  1. “预加载配置” 适合在导入时执行
    在 配置文件如config.py 中 属于 “服务启动时仅需执行一次” 的操作,放在 config.py 的顶层代码中(导入时执行)是最优选择 —— 既无需依赖 main 函数,也无需放在 lifespan 中,且执行时机最早,后续 main.py 或其他模块导入 config 时可直接使用 AGENT_CONFIGS,无运行时阻塞风险。

  2. main 函数仅用于 “自定义启动逻辑”
    不要把 “初始化配置”“连接数据库” 等逻辑放在 main 函数中(除非你必须通过 python main.py 启动且需要自定义参数),因为如果后续用 uvicorn main:app 启动,main 函数不会被执行,可能导致初始化逻辑丢失。

  3. lifespan 适合 “服务级资源管理”
    若你需要在服务启动后、接收请求前做一些 “动态初始化”(比如根据环境变量调整配置、检查外部服务可用性),或在服务停止时释放资源,优先用 lifespan 而非 main 函数 —— 因为 lifespan 是 FastAPI 官方推荐的生命周期管理方式,无论用何种方式启动服务(uvicorn main:app 或 python main.py)都会触发。

总结

启动脚本(如 main.py)被执行 → 执行脚本内的「导入语句」→ 执行脚本内的「顶层代码」→ 启动 FastAPI 应用(uvicorn 等部署时)→ 触发 lifespan(若配置)→ 等待用户请求 → 处理请求

补充

全局变量和lifespan的区别
核心区别:全局变量 vs lifespan
两者的本质差异在于「设计目的」和「执行特性」,具体对比如下:

对比维度main.py 全局变量lifespan 生命周期钩子
核心目的存储「模块级共享数据」(如静态配置、常量),在模块加载时一次性初始化管理「Web 应用生命周期」(启动时初始化资源、关闭时清理资源)
执行时机Python 模块加载时执行(服务启动前),且仅执行 1 次Web 服务启动 / 关闭时执行(服务启动后、关闭前),仅执行 1 次
支持操作类型仅支持「同步操作」(如同步读文件、静态变量赋值)—— 若写异步代码会报错支持「异步操作」(如异步读大文件、异步连接数据库)—— 适配 Web 异步场景
作用域模块级(整个 main.py 及导入它的其他模块可访问)应用级(仅作用于当前 FastAPI 应用实例,与应用生命周期绑定)
资源清理能力无(全局变量创建后,除非手动删除,否则一直驻留内存,服务关闭时也无法主动清理)有(yield 后代码在服务关闭时执行,可主动清理连接、释放资源)

关键场景:什么时候用全局变量?什么时候用 lifespan?

1. 用「全局变量」的场景
  • 存储静态、无 IO 依赖的配置(如超时时间、常量、固定枚举值);
  • 初始化同步、轻量的资源(如小体积的 JSON 配置文件,且服务启动前必须就绪)。
# 全局变量:静态配置(无 IO,轻量)
GLOBAL_CONST = {"MAX_RETRY": 3, "DEFAULT_NAME": "小明"}# 全局变量:同步加载小文件(服务启动前必须就绪)
import json
with open("small_config.json", "r") as f:SMALL_CONFIG = json.load(f)  # 同步读小文件,模块加载时执行
 2.用「lifespan」的场景
  • 处理异步 IO 操作(如异步读大文件、异步连接数据库 / Redis);
  • 管理需要主动清理的资源(如数据库连接池、WebSocket 连接、临时文件);
  • 初始化依赖服务启动后才能获取的资源(如从配置中心拉取动态配置)。
@asynccontextmanager
async def lifespan(app: FastAPI):# 服务启动时:异步加载大文件(避免阻塞模块加载)import aiofilesasync with aiofiles.open("large_data.json", "r") as f:app.state.large_data = json.loads(await f.read())  # 存入应用状态,全局可用# 服务启动后:资源就绪,等待服务运行yield# 服务关闭时:主动清理资源(如关闭数据库连接)await app.state.db_connection.close()

避坑提醒:不要混淆两者的「异步支持」

  • 全局变量不支持异步操作:如果在模块顶层写 await aiofiles.open(...),Python 会直接报错(因为 await 只能在异步函数内使用);
  • lifespan天然支持异步:作为异步上下文管理器(asynccontextmanager 装饰),内部可安全使用 await,避免阻塞事件循环。

总结

  1. 执行顺序main.py 全局变量(模块加载时)→ lifespan(服务启动时);
  2. 核心差异:全局变量是「静态配置容器」,lifespan 是「动态资源管家」;
  3. 选择原则:静态、轻量、同步的用全局变量;异步、需清理、依赖服务的用 lifespan。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94778.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94778.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Fluent Bit系列:字符集转码测试(上)

#作者:程宏斌 文章目录gbk2utf8.lua 脚本说明在主配置中配置过滤器。如何在Linux系统中手动生成GBK日志?验证日志转码的准确性测试测试方案fluent-bit 3.0.2 转换测试这部分内容分为两个任务: 是验证 Lua 脚本是否能够将 GBK 编码的文本转换为…

ApiFox高并发测试用例

介绍 在开发中我们经常会测试高并发场景下的业务,下面来看看如何使用ApiFox编写一个高并发的测试用例 编写接口 第一步我们要编写测试的接口,并且建立一个用例 自动化测试 将上面的测试用例添加到自动化测试中,设置并发参数即可&#xff0c…

【MySQL数据库入门课程】开课啦!

📣 【MySQL数据库入门课程】开课啦! 课程名称:MySQL数据库实战入门(零基础友好版) 开课时间:2025年9月1日 授课方式:线上免费学习 实操练习 教师全程指导 适合人群:中职学校计算机…

面试中的并发编程题(下)

12、synchronized和Lock有什么区别语法层面synchronized是关键字,源码在jvm中,用c实现Lock是接口,源码又jdk提供,用Java实现使用synchronized时,退出同步代码块锁会自动释放,而使用Lock时,需要手…

Autosar之DCM模块

一、DCM介绍 DCM(Diagnostic Communication Manager)是AUTOSAR(汽车开放系统架构)基础软件BSW中服务层(Service Layer)的核心模块,其核心功能是为车辆电子控制单元(ECU)提供符合行业标准(如ISO 14229 UDS、ISO 15765 DoCAN、ISO 15031 OBD等)的诊断服务支持,为开发…

HFSS许可证与版本兼容性

在电磁仿真领域,HFSS(High Frequency Structure Simulator)软件因其卓越的性能和广泛的应用而备受赞誉。然而,为了确保用户能够充分利用HFSS的功能并获得流畅的仿真体验,许可证与版本兼容性成为了不可忽视的重要因素。…

Java有几种文件拷贝方式,哪一种效率最高?

文章目录一、Java文件拷贝的5种方式1. 传统IO流(字节流/字符流)手动拷贝2. NIO的FileChannel拷贝(transferTo/transferFrom)3. Java 7的Files.copy()工具类4. 缓冲流(BufferedInputStream/BufferedOutputStream&#x…

【前端教程】JavaScript 基础总结

JavaScript 的三种使用方式 内部引入(常用)外部引入(一个 js 文件可以被多个页面共同使用)行内(少用) 区别: 内部引入只能够使用单页面外部引入可以应用到多个页面行内是直接在 HTML 标签内写&a…

学习-XMind 思维导图

XMind 是 2006 年诞生的思维导图软件,全球超 1 亿用户,能可视化呈现复杂信息,适用于学习、工作场景。它功能全(支持多图表结构)、易操作、颜值高、跨平台且安全,因此受青睐。其界面有菜单栏(含各…

Ubuntu下MySQL、MongoDB与Redis:从安装到协同的完整指南

目录 一、MySQL:稳定可靠的关系型数据库 1.1 安装与配置 1.2 性能优化实战 二、MongoDB:灵活的文档数据库 2.1 安装与配置 2.2 性能优化策略 三、Redis:高性能内存数据库 3.1 安装与配置 3.2 高级应用场景 四、协同实战&#xff1a…

【传奇开心果系列】Flet框架带图标带交互动画的办公用品费用占比统计饼图自定义模板

Flet带图标带交互动画的办公用品费用占比统计饼图自定义模板 一、效果展示GIF动图 二、应用场景介绍 三、 特色说明 四、小结 五、源码下载地址 一、效果展示GIF动图 二、应用场景介绍 该应用是一个基于 Flet 框架开发的交互式办公用品费用占比统计饼图。适用于以下场景: 企业…

docker镜像在containerd为底座的k8s中使用

docker镜像和container镜像为什么不能直接共通 Docker 镜像和 containerd 镜像本质上格式兼容(都遵循 OCI 镜像规范),但默认情况下 “不能互相识别”,核心原因是存储位置、命名空间和工具链的隔离,而非镜像格式本身的差…

Java-反射机制

在 Java 编程中,“反射” 是一个贯穿基础与进阶的核心概念,它允许程序在运行时动态获取类的结构、调用方法、操作属性,甚至创建对象 —— 无需在编译期明确知道类的具体信息。一、反射是什么?首先明确一个关键定义:Jav…

ARM相关的基础概念和寄存器

目录 1、机器码 2、汇编指令 3、汇编指令集 4、架构 5、内核(CPU中的核心) 6、处理器 7、复杂指令集和精简指令集 7.1复杂指令集 7.2精简指令集 7.3修改 8、内核中的寄存器阻值 8.1溜达存储类型 8.2、AMR处理器(内核&#xff09…

PPT处理控件Aspose.Slides教程:在 C# 中将 PPTX 转换为 Markdown

将您的PowerPoint幻灯片转换为Markdown格式,使其兼容 AI 技术。在这个人工智能驱动的时代,GPT和Claude等大模型能够读取和生成基于 Markdown 的内容。此外,Markdown 还可用于博客文章和文档。因此,作为一名 .NET 开发人员&#xf…

Python 多进程(multiprocessing)

文章目录1. 多进程概述1.1. 多进程的概念1.2. 多进程注意事项2. 进程调用方式2.1. Process 类2.1.1. 构造方法2.1.2. 实例方法2.1.3. 属性2.2. 面向过程2.3. 面向对象3. 进程间通讯3.1. Queues3.2. Pipes3.3. Managers(进行共享数据)4. 进程同步5. 进程池…

推荐系统王树森(五)重排多样性提升

重排01:物品相似性的度量、提升多样性的方法_哔哩哔哩_bilibili github-PPT 前面的讨论中提到 在链路的最后进行重排,重排要插入广告和运营笔记,还要做规则打散,提高推荐的丰富性,比如说一个人特别爱看足球&#xff…

Axios多实例封装

Axios多实例封装方案 我将为您提供一个完整的Axios多实例封装方案,包含基础封装、多实例管理和使用示例。 设计思路 创建基础axios实例封装,支持请求/响应拦截器实现多实例管理器,支持不同API端点配置提供统一的错误处理机制支持请求取消功…

为量化从业者提供免费稳定的股票数据源:免费股票数据API获取实时数据、历史数据与技术指标(含多语言代码指南)实例代码演示与API文档说明

​ 近年来,股票量化分析因其科学、系统的研究方法,日益成为市场热点。而进入这一领域的首要步骤,正是获取全面、准确的股票数据——无论是实时交易行情、历史走势记录,还是企业财务与基本面信息,都是支撑量化策略的核心…

[Sync_ai_vid] UNet模型 | 音频特征提取器(Whisper)

第2章:LatentSync UNet模型 在第1章:唇形同步推理流程中,我们了解到唇形同步推理流程如同电影导演,协调各"专家模块"生成完美唇形同步视频。 本章将深入解析这个"工作室"中最核心的专家——LatentSync UNet…