Flask服务下点击STOP按钮无法退出MODBUS逻辑while循环问题问询
问题根因
- HTTP协议为无状态协议,每次表单提交都是独立的请求。点击START触发的POST请求进入while死循环后,该请求会一直占用服务端线程不返回,后续点击STOP提交的是全新的独立请求,完全无法修改前一个START请求内存中的
state1变量,因此停止条件永远不会触发。 - 原有代码逻辑顺序错误:
break语句放在了关闭资源和打印操作的前面,就算停止条件能触发,close_app_modbus和打印逻辑也永远不会执行。
排查思路
- 加日志确认变量:在while循环内打印
state1的值,可观察到该值永远为None,不会随后续点击STOP按钮发生变化。 - 观察请求状态:点击START后查看浏览器标签页状态,会一直处于加载中,证明前一次请求未完成,服务端被阻塞。
- 走读代码执行顺序:检查if分支内的代码顺序,确认
break会提前终止代码块,后续逻辑无法执行。
解决方案
核心思路是将阻塞的Modbus运行逻辑放到独立线程中执行,用全局状态标记控制启停,不要阻塞HTTP请求线程。
后端代码修改示例
from flask import Flask, request, render_template import threading # 导入你原有依赖 import setup import openapplib import startapplib import closeapplib app = Flask(__name__) # 全局Modbus运行状态标记 modbus_running = False # 任务线程句柄 modbus_task_thread = None def modbus_worker(): global modbus_running while modbus_running: print("MODBUS task running") openapplib.open_app_modbus() startapplib.start_app_modbus() # 循环退出后执行关闭逻辑 closeapplib.close_app_modbus() print("MODBUS task stopped") @app.route("/MODBUS", methods=["GET","POST"]) def mod(): global modbus_running, modbus_task_thread if request.method == "POST": # 原有配置更新逻辑保留 setup.slave_id= request.form.get("slave_id",type=int) setup.port = request.form.get("port",type=str) setup.baudrate= request.form.get("baud_rate",type=int) setup.num_registers= request.form.get("registers",type=int) setup.timeout= request.form.get("timeout",type=int) print(setup.slave_id) print(setup.port) print(setup.baudrate) print(setup.num_registers) print(setup.timeout) setup.setup_modbus() # 处理启动命令 if request.form.get("start_button") == "START" and not modbus_running: modbus_running = True # 新建线程执行任务,不阻塞当前HTTP请求 modbus_task_thread = threading.Thread(target=modbus_worker) modbus_task_thread.daemon = True # 设为守护线程,服务退出时自动销毁 modbus_task_thread.start() # 处理停止命令 elif request.form.get("stop_button") == "STOP" and modbus_running: modbus_running = False # 等待任务线程正常退出 if modbus_task_thread: modbus_task_thread.join() return render_template("modbus.html")
注意事项
- 上述方案适用于单进程部署的Flask服务,如果是多进程部署(如用uWSGI、Gunicorn开多个worker),全局变量会在多个进程中各存一份,此时需要用Redis、本地文件或数据库存储运行状态,不要用内存级全局变量。
- 代码中加了重复启动判断,避免重复创建多个线程执行相同任务。
- 原有HTML表单逻辑不需要修改,直接复用即可正常运行。
内容的提问来源于stack exchange,提问作者Kartik
相关产品推荐
相关产品推荐

