You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何防止FastAPI启动时初始化代码被重复执行两次?

问题原因

重复执行的核心原因是uvicorn.run("main:app")的导入逻辑:运行python main.py时,主进程首先执行一遍main.py所有顶层代码,触发第一次打印;随后uvicorn根据传入的"main:app"字符串重新导入main模块获取app对象,导入过程会再次执行一遍模块顶层代码,触发第二次打印。
如果启动时开启了reload=True,uvicorn会额外启动监控子进程,也会触发代码重复加载,本质都是模块被多次导入导致的。

解决方案

方案1:修改uvicorn启动参数,避免二次导入

把uvicorn.run的第一个参数从模块路径字符串改为直接传入app实例,跳过重新导入模块的步骤:

from fastapi import FastAPI
import uvicorn

app = FastAPI()

print('*' * 80)


@app.get("/")
async def index():
    return {"message": "Welcome to API!"}

if __name__ == '__main__':
    # 直接传app对象,不要传"main:app"字符串
    uvicorn.run(app, host="localhost", port=8000)

修改后直接运行python main.py时,顶层代码只会执行一次。

方案2:用FastAPI生命周期事件管理重开销初始化(推荐)

加载ML模型这类全局只需要执行一次的逻辑,不要写在模块顶层或者if __name__ == '__main__'块里,统一放到FastAPI的lifespan生命周期函数中,不管你是直接运行脚本、还是用命令行uvicorn main:app启动、或是多worker部署,这部分逻辑都只会在应用启动时执行一次,还能统一处理应用关闭时的资源释放:

from contextlib import asynccontextmanager
from fastapi import FastAPI
import uvicorn

# 全局变量存放加载好的模型等重资源
large_ml_model = None

@asynccontextmanager
async def lifespan(app: FastAPI):
    # 应用启动时执行,仅运行一次
    global large_ml_model
    print('*' * 80)
    # 替换为实际的模型加载逻辑
    # large_ml_model = load_your_heavy_model()
    yield
    # 应用关闭时执行,做资源清理
    large_ml_model = None

app = FastAPI(lifespan=lifespan)

@app.get("/")
async def index():
    return {"message": "Welcome to API!"}

if __name__ == '__main__':
    uvicorn.run(app, host="localhost", port=8000)

方案3:非必要不开启reload模式

开发时如果开了reload=True,uvicorn会启动监控进程和应用进程两个进程,两个进程都会加载代码,会导致顶层逻辑执行两次。生产环境必须关闭reload,开发场景下如果开启reload,更要把重初始化逻辑放到lifespan中,避免重复加载浪费内存。

提示:不要把重初始化逻辑写在if __name__ == '__main__'块中,当你用命令行uvicorn main:app启动服务时,这个块里的代码完全不会执行,会导致初始化逻辑失效。

内容的提问来源于stack exchange,提问作者abhinavkulkarni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 10:09:15