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

为什么Flask应用的线程在跳出while循环后仍持续运行?

问题根因

你遇到的现象本质是跨请求的线程控制逻辑完全失效,核心问题有3个:

  • 你把threading.Event实例和工作线程都定义在了视图函数内部,每次请求接口都会创建全新的flag对象和线程对象,不同请求之间的实例完全隔离。你调用start=false时clear的是本次请求新建的flag,对之前start=true时已经启动的老线程持有的flag没有任何影响,老线程的flag一直是set状态,会无限运行。
  • 视图函数中调用了t.join(),会直接阻塞当前请求的响应,直到工作线程执行完毕。如果用Flask默认单线程模式,第一个start=true的请求会直接占满服务资源,后续所有请求都无法被处理。
  • 你看到的done日志是start=false请求新建的线程输出的,这个线程持有的flag一开始就是clear状态,所以直接执行到print('done')就退出了,后面继续输出的running是之前启动的老线程一直没停产生的日志,并不是线程重启了。

修复方案

把控制用的Event实例、工作线程实例都放到全局作用域,保证所有请求共享同一个控制对象,同时避免重复创建线程:

import threading
import time
from flask import Flask, request

app = Flask(__name__)
# 全局控制flag和工作线程实例
run_flag = threading.Event()
work_thread = None

def run():
    while run_flag.is_set():
        print('running')
        time.sleep(1)
    print('done')

@app.route('/')
def index():
    global work_thread
    status = request.args.get('start', default='false', type=str)
    
    if status == 'true':
        # 避免重复启动线程
        if work_thread is None or not work_thread.is_alive():
            run_flag.set()
            work_thread = threading.Thread(target=run)
            work_thread.start()
    else:
        # 停止线程
        run_flag.clear()
        # 可选:等待线程完全退出再返回,不需要可以删掉下面两行
        if work_thread and work_thread.is_alive():
            work_thread.join()
    
    return status

if __name__ == '__main__':
    # 不要开debug模式,否则会启动两个进程导致线程控制失效
    app.run(debug=False)

注意事项

  • 不要开启Flask的debug模式,debug模式默认会启动重载进程,会存在两个服务进程,全局变量不共享,导致控制逻辑失效。生产环境使用Gunicorn等WSGI服务器时,注意要配置工作进程数为1,或者用跨进程的控制方案(比如Redis存状态)。
  • 上述方案仅适用于单进程部署场景,如果是多进程部署,需要用分布式状态存储来替换threading.Event实现控制。

内容的提问来源于stack exchange,提问作者D Park

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 14:18:03