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

Python中是否使用`__name__`判断的差异:FastAPI+Uvicorn启动报地址已占用问题排查

两种代码写法的底层执行逻辑差异

无if __name__包裹的异常写法执行流程

  • 执行python main.py启动的首个进程,__name__属性为"__main__",会无差别执行所有顶层代码
  • 执行到顶层uvicorn.run(...)时,因开启reload模式,当前进程会转为Uvicorn的reload监控主进程,负责文件变更监听、拉起实际提供服务的Worker进程
  • 由于传入的应用标识是字符串形式的"main:app",Uvicorn reload模式不会复用当前进程已加载的app对象,会重新触发一次main模块的导入流程,这次导入产生的模块上下文__name__为"main",而非"__main__"
  • 因为没有执行边界判断,这次模块导入过程会再次跑到uvicorn.run(...)逻辑,等同于在同一条执行链路里启动了两个独立的Uvicorn服务实例,两个实例同时尝试绑定8080端口,触发地址占用报错
  • 报错发生时绑定失败的进程会直接退出,端口占用是瞬时状态,后续用lsof等工具排查时,已经找不到残留的占用进程

加if __name__判断的正常写法执行流程

  • 直接执行python main.py时,首个进程__name__为"__main__",满足分支判断条件,仅执行一次uvicorn.run启动reload监控主进程
  • 当reload监控主进程重新导入main模块拉取app对象时,被导入的模块上下文__name__为"main",不满足分支判断条件,uvicorn.run逻辑完全不会被重复触发
  • 整个流程仅启动一个Uvicorn实例,没有重复的端口绑定请求,自然不会出现地址占用报错
报错的根本原因

核心触发逻辑来自Uvicorn reload模式的特殊实现:它必须通过字符串形式的应用标识,在启动阶段重新导入业务模块获取app对象,不会直接复用启动进程里已存在的对象。如果没有通过__name__判断给启动逻辑加上执行边界,就会在模块导入的过程中重复触发启动流程,造成同执行链路内的端口抢占。

补充说明:代码中写的reload="true"是字符串类型,Uvicorn的reload参数实际接收布尔值,虽然多数版本会做自动类型兼容,但建议直接传reload=True避免潜在的参数解析问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.25 08:27:07