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

生产模式下运行Flask应用时如何终止无限循环

Flask应用uWSGI部署后无法停止后台循环的问题解决

问题场景

开发了一个带有Start和Stop按钮的Flask应用,核心需求:

  • 点击Start按钮,程序持续打印pStart(无限循环输出)
  • 点击Stop按钮,停止打印;再次点击Start可恢复打印

本地开发模式下功能正常,但使用uWSGI部署到生产环境后,Stop按钮无法终止打印循环,程序会一直输出pStart。

原始代码

Flask主程序(myproject.py)

from flask import Flask, render_template
import sys
flag1=True
app = Flask(__name__)

@app.route('/')
def index():
  return render_template('index.html')

@app.route('/start/')
def start():
  globals()['flag1']=True
  while flag1==True:
    print('pStart')
  return render_template('index.html')

@app.route('/stop/')
def stop():
  globals()['flag1']=False
  return render_template('index.html')

if __name__ == '__main__':
  app.run(host='0.0.0.0')

前端模板(templates/index.html)

<!doctype html>

<head>
    <title>Test</title> 
    <meta charset=utf-8>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

    </head>
    <body>
        <h1>My Website</h1>

<script type=text/javascript>
        $(function() {
          $('a#test').on('click', function(e) {
            e.preventDefault()
            $.getJSON('/start',
                function(data) {
              //do nothing
            });
            document.getElementById('btn1').disabled = true;
            document.getElementById('btn2').disabled = false;
            return false;
          });
        });
</script>

<script type=text/javascript>
        $(function() {
          $('a#test1').on('click', function(e) {
            e.preventDefault()
            $.getJSON('/stop',
                function(data) {
              //do nothing
            });
            document.getElementById('btn1').disabled = false;
            document.getElementById('btn2').disabled = true;
            return false;
          });
        });
</script>

<div class='container'>
        <form>
            <a href=# id=test><button id='btn1' class='btn btn-default'>Start</button></a>
        </form>
</div>  
<p>
<p>
<div class='container'>
        <form>
            <a href=# id=test1><button id='btn2' class='btn btn-default' type="button" disabled>Stop</button></a>
        </form>
</div>  
    </body>

WSGI入口文件(wsgi.py)

from myproject import app

if __name__ == "__main__":
    app.run()

原始uWSGI启动命令

uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app

问题根源

原始代码在/start/路由的请求处理线程中直接运行无限循环,阻塞了该线程的请求响应流程;同时uWSGI默认未启用多线程支持,导致后续的/stop/请求无法被及时处理,全局变量的修改也无法同步到被阻塞的线程,最终造成Stop按钮失效。

解决方法

通过引入线程分离后台任务与请求处理,并开启uWSGI的多线程支持,实现功能正常运行。

修改后的Flask代码

from flask import Flask, render_template
import threading
import time
from werkzeug.serving import make_server
import signal
import sys

app = Flask(__name__)
threads = []
stop_flags = []

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/start/')
def start():
    stop_flags.append(False)
    thread = threading.Thread(target=run_loop, args=(len(stop_flags) - 1,))
    threads.append(thread)
    thread.start()
    return render_template('index.html')

@app.route('/stop/')
def stop():
    if stop_flags:
        stop_flags[-1] = True
    return render_template('index.html')

def run_loop(thread_id):
    while not stop_flags[thread_id]:
        print('pStart')
        time.sleep(0.5)

def signal_handler(signum, frame):
    for thread in threads:
        thread.join()
    server.shutdown()
    sys.exit(0)

if __name__ == '__main__':
    signal.signal(signal.SIGTERM, signal_handler)
    signal.signal(signal.SIGINT, signal_handler)
    server = make_server('0.0.0.0', 5000, app)
    server.serve_forever()

调整后的uWSGI启动命令

uwsgi --socket 0.0.0.0:5000 --protocol=http --enable-threads -w wsgi:app

关键改动说明

  • 将无限循环任务放到独立线程中执行,避免阻塞Flask的请求响应主线程
  • 添加--enable-threads参数,让uWSGI支持多线程运行环境
  • 使用列表存储每个线程的停止标志,确保线程间的状态同步可控

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 01:48:28