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

如何实现运行时每日更新sklearn、PyTorch模型/向量,规避文件打开过多报错

方案实现

核心思路

  • 用全局变量缓存已加载的模型实例,避免每次请求重复加载,从根源解决文件描述符溢出问题
  • 加读写锁保证并发场景下模型读取、切换的安全性,读多写少场景下性能损失极低
  • 版本切换时优先加载当日版本,加载失败自动降级到已有版本,完全匹配可用性约束

具体实现步骤

1. 依赖准备

除你已有的fastapi、joblib依赖外,额外用到两个工具库:readerwriterlock处理读写锁,APScheduler做定时检测(如果用主动触发更新的方式可以不装后者)

pip install readerwriterlock apscheduler

2. 全局缓存与服务初始化

from fastapi import FastAPI
from readerwriterlock import rwlock
from datetime import date
import joblib
import os

app = FastAPI()

# 全局模型缓存结构
MODEL_CACHE = {
    "current_version": None,
    "model_instance": None
}
# 读写锁,读请求不互斥,仅切换模型时加写锁
RW_LOCK = rwlock.RWLockWrite()
# 模型文件路径模板,按实际存储规则修改
MODEL_PATH_TPL = "./models/model_{date_str}.joblib"

def load_model_by_date(target_date: date):
    """按指定日期加载模型,文件不存在/加载失败返回None"""
    date_str = target_date.strftime("%Y%m%d")
    model_path = MODEL_PATH_TPL.format(date_str=date_str)
    if not os.path.exists(model_path):
        return None
    try:
        return joblib.load(model_path)
    except Exception:
        return None

# 服务启动时初始化最近可用模型
def init_model():
    # 优先加载当日模型,失败则加载昨日模型
    today = date.today()
    model = load_model_by_date(today)
    if model:
        MODEL_CACHE["current_version"] = today
        MODEL_CACHE["model_instance"] = model
        return
    yesterday = today.replace(day=today.day-1)
    model = load_model_by_date(yesterday)
    if not model:
        raise RuntimeError("无可用模型文件,服务启动失败")
    MODEL_CACHE["current_version"] = yesterday
    MODEL_CACHE["model_instance"] = model

init_model()

3. 模型更新逻辑

两种触发方式二选一即可:

方式一:主动触发(最优,无额外开销)

应用内负责生成模型的模块,写完当日模型文件后直接调用更新函数即可,时效性最高

def update_model():
    """尝试切换到当日版本模型,加载失败自动保留旧版本"""
    today = date.today()
    # 已经是当日版本无需重复更新
    if MODEL_CACHE["current_version"] == today:
        return
    new_model = load_model_by_date(today)
    if not new_model:
        return
    # 加写锁替换模型,避免并发读取异常
    with RW_LOCK.gen_wlock():
        MODEL_CACHE["current_version"] = today
        MODEL_CACHE["model_instance"] = new_model

方式二:定时轮询(低耦合,适合模块拆分场景)

启动后台定时任务,定期检查当日模型是否就绪,无需和模型生成模块做逻辑耦合

from apscheduler.schedulers.background import BackgroundScheduler

@app.on_event("startup")
def start_check_scheduler():
    scheduler = BackgroundScheduler()
    # 每10分钟检查一次模型更新,可根据实际需求调整间隔
    scheduler.add_job(update_model, "interval", minutes=10)
    scheduler.start()

4. 接口调用逻辑

接口请求时加读锁获取模型,读锁不互斥,不会影响高并发场景下的接口性能

@app.post("/predict")
def predict(input_text: str):
    # 加读锁获取模型,多个请求可同时持有读锁
    with RW_LOCK.gen_rlock():
        model = MODEL_CACHE["model_instance"]
    # 执行推理逻辑
    result = model.predict([input_text])
    return {"result": result[0]}

额外注意事项

  • 生成模型文件时做原子操作:先写入后缀为.tmp的临时文件,写完再重命名为正式的.joblib文件,避免更新逻辑读取到未写完的损坏文件
  • 可定期清理超过7天的历史模型文件,避免磁盘占用过高
  • 若模型体积较大加载时间长,可以先异步加载完成后再替换全局缓存,全程不会阻塞线上请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 08:12:01