Python中Gunicorn搭配Flask启动后进程挂起问题求助
你遇到的核心问题明显出在Gunicorn多进程环境和TensorFlow/Keras模型加载的交互上——毕竟单独跑Flash一切正常,说明模型和业务逻辑本身没问题。下面是几个经过验证的实用解决思路:
1. 延迟模型加载到首次请求时
Gunicorn启动worker阶段就加载模型很容易引发阻塞:一方面模型加载(尤其是大模型)耗时久,容易触发Gunicorn的超时判定;另一方面TensorFlow的初始化逻辑在多进程环境下容易和worker进程产生资源冲突。我们可以把模型加载推迟到第一个请求进来的时候,避开worker启动的敏感阶段。
示例代码:
from flask import Flask import tensorflow as tf from keras.models import load_model app = Flask(__name__) # 先初始化模型为None,不提前加载 model = None @app.before_first_request def load_model_on_first_request(): global model # 先限制TensorFlow的线程数,避免和Gunicorn的worker抢占CPU资源 tf.config.threading.set_intra_op_parallelism_threads(1) tf.config.threading.set_inter_op_parallelism_threads(1) # 加载你的Keras模型 model = load_model('your_trained_model.h5') @app.route('/predict') def make_prediction(): if not model: return "Model is still loading", 500 # 这里编写你的预测逻辑 return "Prediction result here"
2. 调整Gunicorn的Worker配置
先从单worker开始验证是否是多进程冲突的问题,同时指定同步worker类型(避免异步worker和TensorFlow的线程模型冲突),并调高超时时间给模型加载留足空间:
gunicorn --workers=1 --worker-class=sync --timeout=120 app:app
你之前调低超时时间的操作反而会让Gunicorn更快判定worker启动失败,加重问题,所以这里要反过来调高超时。如果单worker运行正常,再逐步增加worker数量,注意每个worker都会加载独立的模型实例,要确保服务器内存足够。
3. 限制TensorFlow的资源占用
TensorFlow默认会尝试占用所有可用的CPU线程和内存,这很容易和Gunicorn的worker进程产生资源竞争,导致死锁或挂起。除了上面在模型加载前设置线程数,还可以限制内存增长:
# CPU环境下的配置 tf.config.set_soft_device_placement(True) tf.config.experimental.set_memory_growth(tf.config.list_physical_devices('CPU')[0], True) # 旧版本TensorFlow可用Session配置 session_conf = tf.ConfigProto( intra_op_parallelism_threads=1, inter_op_parallelism_threads=1, allow_soft_placement=True ) sess = tf.Session(config=session_conf) keras.backend.set_session(sess)
4. 禁用Gunicorn的--preload参数
如果你之前启动时加了--preload(预加载应用),这个参数会让主进程先加载模型再fork worker进程,但TensorFlow的计算图和会话在fork后的子进程中无法正常工作,直接导致worker挂起,务必去掉这个参数。
建议先从延迟模型加载和调整Gunicorn基础配置开始尝试,这两个方案解决过绝大多数类似的部署问题。
内容的提问来源于stack exchange,提问作者Rehan Aziz

