
2 个版本,都没有解决内存持续增加,由于内存一直增加,最后因为小鸡内存不足而被杀掉。
这是一个加载训练后的模型,通过网络传入预测参数,然后返回预测 json 结果。
求大佬帮忙看看问题出在哪里,谢谢。
这是 chatgpt 4.0 给的版本
from flask import Flask, request, jsonify import pickle import os import psutil import pandas as pd app = Flask(__name__) class SingletonModel: _instance = None def __new__(cls): if cls._instance is None: print("Creating Singleton Instance") cls._instance = super(SingletonModel, cls).__new__(cls) modelName = "xgboost_model-k.pkl" with open(modelName, "rb") as pkl_file: loaded_data = pickle.load(pkl_file) cls._instance.model = loaded_data['model'] cls._instance.scaler = loaded_data['scaler'] cls._instance.label_encoder = loaded_data['label_encoder'] cls._instance.feature_names = ['shortAvg','longAvg','volatility','diff'] return cls._instance resources = SingletonModel() model = resources.model scaler = resources.scaler label_encoder = resources.label_encoder @app.route('/predict', methods=['POST']) def predict(): global model, scaler, label_encoder data = request.json['input'] df = pd.DataFrame([data], columns=resources.feature_names) scaled_data = scaler.transform(df) prediction = model.predict(scaled_data) label_prediction = label_encoder.inverse_transform(prediction) return jsonify([label_prediction[0]]) if __name__ == '__main__': app.run(port=6601,debug=True) 这是 Claude 给的版本
import asyncio from flask import Flask, request, jsonify import pickle import pandas as pd app = Flask(__name__) # 模型相关全局变量 model = None scaler = None label_encoder = None async def load_model(): global model, scaler, label_encoder,feature_names if not model: with open('xgboost_model-k.pkl', 'rb') as f: loaded_data = pickle.load(f) model = loaded_data['model'] scaler = loaded_data['scaler'] label_encoder = loaded_data['label_encoder'] feature_names = ['shortAvg','longAvg','volatility','diff'] async def predict(data): await load_model() df = pd.DataFrame([data], columns=feature_names) scaled_data = scaler.transform(df) prediction = model.predict(scaled_data) label_prediction = label_encoder.inverse_transform(prediction) return label_prediction[0] @app.route('/predict', methods=['POST']) async def predict_handler(): data = request.json['input'] result = await asyncio.gather(predict(data)) return jsonify(result) if __name__ == '__main__': app.run(port=6601,debug=False) 使用常规uWSGI也无法解决内存持续增加问题,但是,

1 missz 2023-09-25 17:10:13 +08:00 我用 flask 启的 yolo5 的接口也是内存无限增长,用 memory_profiler 也看不出具体增长原因,现在是用个 shell 脚本超过一定内存就 kill 重启 |
2 jstony 2023-09-25 17:35:17 +08:00 换个版本,cpython 的底层还是 c ,就不能避免完全没有内存泄漏,而且一大堆库,质量良莠不齐。 |
3 davinci21s OP |
4 wynemo 2023-09-25 20:18:06 +08:00 用 uwsgi ,flask 自带的就是这样 |
5 Inzufu 2023-09-25 22:19:25 +08:00 via Android 跑大项目不建议用 py ,还是 nodejs 靠谱一点儿,这两个语言其实学起来差不多。 |
6 roycestevie6761 2023-09-25 22:28:42 +08:00 python 就这样的啦 |
7 among 2023-09-25 22:34:54 +08:00 uwsgi ,多进程模式,配置超过多少内存,就 fork 一个新的进程。 |
8 ynkkdev 2023-09-25 22:35:02 +08:00 @inzufu 这玩意一眼就是算法推理服务,nodejs 加载模型文件跑算法推理,你这不是难为算法同学吗? 这代码里面一眼看去就是模型资源全局变量跑,十几个并发,要是没有 gpu 没有显存,就是需要大内存的。再就是推理接口一般也都是 batch 推理,并发可以利用 batch 来缓解压力。 简而言之,要么懂算法、要么懂 pthon 后端,两者都不精通,算法服务能跑起来已经谢天谢地,就不要苛责性能了 |
10 Mystery0 2023-09-26 09:49:35 +08:00 via Android 蹲一个,我也遇到这个问题,照着别人的代码训练了一个模型然后用 flask 提供接口调模型预测数据 运行之后内存就会慢慢变大,现在的解决办法是隔段时间看一下内存,超过 6-700mb 就重启一下 |
11 davinci21s OP |
12 yagamil 2023-09-26 12:12:54 +08:00 model, scaler, label_encoder,feature_names 这几个变量用全局, 如果不同请求过来, 里面的模型一些参数会被其他进程的请求给修改掉么? |
13 wxlpure 2023-09-26 12:52:29 +08:00 flask 不是同步框架吗?同步框架内用异步是啥效果? |
14 davinci21s OP |
16 nonduality 2023-09-26 17:11:48 +08:00 对 Claude 写的不评价,对 ChatGPT 写的说点看法。 单例模式在这里应该是没用的,你可以把 print 的内容改为输出到日志( logging.info ),然后在日志里查看是否不断创建 SingletonModel 。 解决方案之一是利用 RPC:在后台启动一个常驻的数据处理服务,负责接收请求、数据处理和返回结果; Flask 负责把客户端请求转发到常驻服务,再把返回来的结果发给客户端。 需要注意的是,RPC 有多种执行模式,你要避免不断 fork 进程或 spawn 线程去处理数据,这样内存占用也有可能不断膨胀,而要直接调用数据处理的入口函数,这时候单例模式就能起作用。 |
17 davinci21s OP @nonduality 感谢,可以对遇到相同问题的提供参考。 |
18 subjadeites 2023-09-26 18:32:58 +08:00 via Android 用 gunicorn 试试? |
19 subjadeites 2023-09-26 18:33:46 +08:00 via Android import gevent.monkey gevent.monkey.patch_all() import multiprocessing debug = False loglevel = 'info' bind = '0.0.0.0:7000' pidfile = 'logs/gunicorn.pid' logfile = 'logs/debug.log' # 启动的进程数 workers = multiprocessing.cpu_count() * 2 worker_class = 'gunicorn.workers.ggevent.GeventWorker' preload_app = True x_forwarded_for_header = 'X-FORWARDED-FOR' |
20 zheng5200 2023-09-27 10:35:01 +08:00 via iPhone gunicorn 起 flask 也有这个问题,也是通过--max-requests 解决的,() |