Flask中使用Threading并行训练模型失效问题求助
问题:Flask中使用threading实现模型训练并行失败
在Flask中尝试用threading实现模型并行训练,测试代码(含sleep循环)能正常并行并返回状态,但替换为实际的模型训练函数后,必须等待训练完成才会继续执行,无法实现并行。
测试代码:
from threading import Thread from time import sleep def model_training(): global status for i in range(1, 11): status = i sleep(1) @app.route('/retrain/', methods=['GET', 'POST']) def retrain(): for th in threading.enumerate(): if th.name == "training": print("Thread still running") message = "Training is already in progress" break else: print("Starting a new job thread") message = "Training started" t1 = Thread(target=model_training, name="training") t1.start() return render_template('retrain.html', message=message, models=model_files, num_images=id)
实际模型训练函数:
def model_train(): dataset, model_config, label_mapping = load_config() print("Training: start.") model = model_config.model model.fit() print("Training: end.")
解决方向
核心原因:Python GIL与任务类型不匹配
- 测试用的
model_training是IO密集型任务:sleep()会主动释放全局解释器锁(GIL),让其他线程有机会执行,所以Flask主线程能立即返回响应,实现并行效果。 - 实际的
model_train是CPU/GPU密集型任务:model.fit()执行时,会持续占用GIL(CPU训练场景),导致Python的线程无法真正并行;如果是GPU训练,框架本身可能会占用主线程资源,或者内部线程管理覆盖了你的自定义线程,最终表现为Flask主线程被阻塞,必须等训练结束才返回。
具体解决办法
1. 改用multiprocessing替代threading
多进程绕过GIL限制,每个进程拥有独立的Python解释器和内存空间,适合处理CPU/GPU密集型任务。示例代码:
from multiprocessing import Process def model_train(): # 原模型训练代码 dataset, model_config, label_mapping = load_config() print("Training: start.") model = model_config.model model.fit() print("Training: end.") @app.route('/retrain/', methods=['GET', 'POST']) def retrain(): # 检查是否已有训练进程在运行 from multiprocessing import active_children training_running = False for p in active_children(): if p.name == "training": training_running = True break if training_running: message = "Training is already in progress" else: message = "Training started" p1 = Process(target=model_train, name="training") p1.start() return render_template('retrain.html', message=message, models=model_files, num_images=id)
注意:多进程下全局变量不共享,若需要跟踪训练状态,需用共享内存、文件锁或数据库等外部存储方式。
2. 利用框架自身的异步/多进程支持
比如TensorFlow的model.fit()可以设置workers和use_multiprocessing=True参数,启用多进程数据加载;但这只是优化数据处理环节,若要让训练完全不阻塞Flask主线程,依然推荐用独立的训练进程。
3. 进阶:使用任务队列管理训练任务
如果需要更可靠的任务调度、状态跟踪、失败重试,可采用Celery+Redis(或RabbitMQ)的方案:
- Flask作为任务生产者,将训练任务提交到队列
- 后台启动独立的worker进程执行训练任务
- 通过数据库或缓存记录训练状态,Flask接口可查询状态并返回给前端
内容的提问来源于stack exchange,提问作者iamkk
相关产品推荐
相关产品推荐

