You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask服务下点击STOP按钮无法退出MODBUS逻辑while循环问题问询

问题根因
  1. HTTP协议为无状态协议,每次表单提交都是独立的请求。点击START触发的POST请求进入while死循环后,该请求会一直占用服务端线程不返回,后续点击STOP提交的是全新的独立请求,完全无法修改前一个START请求内存中的state1变量,因此停止条件永远不会触发。
  2. 原有代码逻辑顺序错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 17:36:02