应使用单 worker 启动:uvicorn main:app --workers 1 --loop uvloop --http httptools,并配合异步批处理与 cuda_visible_devices 绑定,避免 fork 导致的 cuda 上下文崩溃和显存虚高。

FastAPI 启动时如何避免 PyTorch 多进程加载模型崩溃
直接在 main.py 顶层 import 模型或调用 torch.load(),会导致每个 uvicorn worker 进程重复加载模型、抢占显存,甚至触发 OSError: [Errno 12] Cannot allocate memory。根本原因是 PyTorch 的 CUDA 上下文不支持 fork —— 而 uvicorn 默认用 fork 方式启动多进程(--workers N)。
正确做法是:延迟加载模型,且确保只在主进程初始化后、worker 进程首次请求时加载一次。推荐用单例 + threading.Lock 控制初始化时机:
from threading import Lock
_model = None
_model_lock = Lock()
<p>def get_model():
global _model
if _model is None:
with _model_lock:
if _model is None:
_model = torch.jit.load("model.pt").eval()
_model.to("cuda" if torch.cuda.is_available() else "cpu")
return _model
</p>
注意:torch.jit.load 比 torch.load 更适合部署,它跳过 Python 解释器依赖,序列化后更稳定;若必须用 torch.load,请确保保存时用了 torch.save(model, ..., _use_new_zipfile_serialization=True) 并禁用 pickle。
怎么让多个并发请求自动聚合成 batch 推理(而不是逐条 infer)
FastAPI 默认每请求一个协程,PyTorch 单次 forward 处理单样本效率极低。你不能靠 client 端拼 batch —— 实际业务中请求来源不可控。得在服务端做「请求缓冲」+「异步批处理」。
核心思路:用 asyncio.Queue 缓冲短时间内的请求,由后台 task 统一拉取、pad/stack、推理、分发结果。关键参数要调好:
-
max_wait_ms=50:最长等 50ms,避免小流量下无限等待 -
max_batch_size=32:GPU 显存能扛住的最大 batch,超了立刻触发推理 - 所有请求必须带
id字段,用于结果回填,否则无法区分响应归属
示例结构(省略完整队列管理代码):
async def batch_processor():
while True:
batch = []
start = time.time()
while len(batch) <h3>uvicorn 启动时该用 --workers 还是 --loop uvloop --http httptools</h3><p>结论:别用 <code>--workers</code> 启 PyTorch 服务。它强制 fork,CUDA 初始化失败率高;即使加 <code>--preload</code>,各 worker 的 CUDA context 仍相互隔离,<code>torch.cuda.memory_allocated()</code> 会虚高,OOM 风险翻倍。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill7657" title="python 查询技能"><img
src="https://img.php.cn/upload/skill/000/000/081/179161384046229.jpg" alt="python 查询技能" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill7657" title="python 查询技能" class="overflowclass">python 查询技能</a>
<p class="overflowclass">查询客流数据,输出JSON格式,可直接导入Bitable等可视化工具</p>
</div>
<a rel="nofollow" href="/xiazai/skill7657" title="python 查询技能" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><p>正确姿势是:单 worker + 异步批处理 + GPU 绑定:</p>
- 启动命令用:
uvicorn main:app --host 0.0.0.0 --port 8000 --loop uvloop --http httptools --workers 1 - 确保
CUDA_VISIBLE_DEVICES=0提前设置,避免多卡干扰 - 如果 CPU 密集(如图像 decode),可额外开 1–2 个
concurrent.futures.ProcessPoolExecutor做预处理,但 inference 必须留在主线程/GPU 线程
实测:在 A10G 上,单 worker + 批处理比 4 workers + 单样本快 3.2 倍,显存占用降 60%。
客户端并发压测时出现 ConnectionResetError 或 timeout 怎么定位
这不是 FastAPI 或 PyTorch 的错,大概率是中间层(nginx / ALB / client SDK)默认超时太短,或未配置 keepalive。典型现象:ConnectionResetError: [Errno 104] Connection reset by peer 出现在 client,但 server 日志无报错。
排查顺序:
- 先关掉所有代理,
curl -v http://localhost:8000/predict直连验证基础通路 - 检查 uvicorn 日志里是否有
connection closed或client disconnected—— 有则说明 client 主动断了 - 确认 client 是否复用 session:Python requests 要显式用
Session(),HTTP/1.1 默认不 keepalive - 若走 nginx,必须加:
proxy_http_version 1.1; proxy_set_header Connection '';,否则它会把长连接转成短连接
批处理服务的响应时间波动大(比如 10ms~500ms),对 timeout 敏感。建议 client 设置 timeout=(3.0, 30.0)(connect + read),而非固定 5s。
真正难调的是 batch 边界和 GPU 利用率之间的平衡——等太久,延迟高;等太急,GPU 利用率低。这个阈值没有银弹,得按你的 QPS 和显卡型号实测。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










