如何在Flask应用中实现定时任务并解决multiprocessing高CPU占用问题
核心问题原因
你当前CPU占用过高的核心诱因是代码存在进程重复启动的逻辑错误:
- 全局作用域直接执行了两行
multiprocessing.Process启动逻辑,同时if __name__ == '__main__'块内又重复启动了一次两个进程,在多进程模式部署(尤其是gunicorn派生worker时)会导致大量重复的拉数据、训练进程被创建,无限抢占CPU资源。 - 你将定时任务逻辑和Flask Web服务的入口耦合,使用gunicorn部署时
if __name__ == '__main__'块的代码不会被执行,全局的进程启动逻辑会被每个worker重复加载执行,进一步放大进程冗余问题。
优化方案
1. 解耦定时任务与Web服务(最优先推荐)
不要把数据拉取、模型训练的定时逻辑和Web请求处理服务放在同一个部署入口,二者完全独立运行互不影响:
- 数据拉取、模型训练逻辑单独写成独立的Python脚本
- 用系统自带的crontab配置定时执行规则:
- 每分钟执行一次数据拉取脚本:
* * * * * /usr/bin/python3 /path/to/your/fetch_script.py - 每12小时执行一次模型训练脚本:
0 */12 * * * /usr/bin/python3 /path/to/your/retrain_script.py
- 每分钟执行一次数据拉取脚本:
- 训练完成后新模型保存到固定路径,Flask服务做热加载更新即可,无需重启服务。
这种方案完全避免了定时任务和Web服务抢资源,也不会出现任务重复执行的问题,稳定性最高。
2. 修复现有代码逻辑(如果暂时不想解耦)
如果要保留当前代码内调度的模式,先做以下修改:
- 删除全局作用域的两行
multiprocessing.Process(target=xxx).start()代码,仅保留if __name__ == '__main__'块内的进程启动逻辑 - 启动gunicorn时设置
preload_app = True参数,保证代码只预加载一次,避免多worker重复启动后台进程 - 给训练进程设置CPU使用限制,比如用
psutil库限制进程的CPU核心占用,或者启动进程时用nice命令调低进程优先级,避免训练时占满CPU影响接口响应。
3. 模型训练侧优化
针对10万条数据集的LSTM训练,可以进一步降低资源占用:
- 采用小批量(mini-batch)训练,不要一次性加载全量数据集到内存计算
- 给深度学习框架设置CPU线程数限制:
- TensorFlow:
tf.config.threading.set_intra_op_parallelism_threads(2)、tf.config.threading.set_inter_op_parallelism_threads(2) - PyTorch:
torch.set_num_threads(2)
- TensorFlow:
- 采用增量训练模式,不需要每次都用全量数据从头训练,基于上一次的模型权重用新数据微调即可,大幅降低训练耗时和CPU占用。
4. 替换自研定时逻辑
不要用死循环+sleep的方式实现定时,很容易出现时间漂移、进程异常退出不重启的问题,可以用成熟的定时任务库APScheduler,支持cron表达式配置任务,还可以加分布式锁保证多实例部署下任务只执行一次,比自研逻辑稳定性高很多。
内容的提问来源于stack exchange,提问作者Muhammad Daniyal
相关产品推荐
相关产品推荐

