如何在Flask中启动线程而不导致页面冻结?
解决Flask中下载任务阻塞页面加载的问题
核心问题分析
你当前代码的关键错误是线程创建方式错误:
threads.append(threading.Thread(target=downloader(h)))
这里downloader(h)会直接在主线程(Flask请求线程)中执行函数,而非把函数作为线程的目标任务。主线程会一直等待downloader执行完成,导致页面持续加载。
快速修复:正确使用线程
修改app.py中的线程创建逻辑,将函数对象传给target,用args传递参数,并设置守护线程避免资源残留:
# app.py from flask import request, flash import threading from downloader import downloader # 路由函数内的代码 content = request.form['downloads'] # 简化字符串处理:过滤空行,去除每行首尾空白 info_hashes = [h.strip() for h in content.strip().split('\n') if h.strip()] threads = [] try: for h in info_hashes: # 正确创建线程:传递函数引用,参数放入args元组,设置daemon=True thread = threading.Thread(target=downloader, args=(h,), daemon=True) threads.append(thread) thread.start() flash('Download started.') except Exception as e: flash(str(e))
关键修改点:
target=downloader:传递函数本身,而非立即执行函数args=(h,):以元组形式传递函数参数(注意末尾逗号,避免被解析为单个变量)daemon=True:标记为守护线程,当Flask主进程结束时自动退出,防止残留后台线程
生产环境进阶方案:使用异步任务队列
线程方案在开发环境可以临时解决问题,但生产环境(如使用Gunicorn、uWSGI等WSGI服务器)中,线程管理容易出现问题(比如worker重启导致任务中断)。更可靠的方式是使用异步任务队列,比如Celery:
步骤1:安装依赖
pip install celery redis
步骤2:配置Celery
# celery_config.py from celery import Celery def make_celery(app): celery = Celery( app.import_name, broker='redis://localhost:6379/0', # 消息队列 backend='redis://localhost:6379/0' # 任务结果存储(可选) ) celery.conf.update(app.config) return celery
步骤3:改造Flask应用
# app.py from flask import Flask, request, flash, redirect, url_for from celery_config import make_celery from downloader import downloader app = Flask(__name__) app.secret_key = 'your-secret-key-here' # 必须设置才能使用flash celery = make_celery(app) # 将下载函数包装为Celery异步任务 @celery.task def async_download(info_hash): downloader(info_hash) @app.route('/start-download', methods=['POST']) def start_download(): content = request.form['downloads'] info_hashes = [h.strip() for h in content.strip().split('\n') if h.strip()] try: for h in info_hashes: async_download.delay(h) # 将任务发送到队列,立即返回 flash('Download tasks submitted successfully.') except Exception as e: flash(f'Error submitting tasks: {str(e)}') return redirect(url_for('index')) # 跳回页面,避免重复提交
步骤4:启动Celery Worker
在终端中运行:
celery -A app.celery worker --loglevel=info
这样下载任务会完全由独立的Celery Worker进程处理,Flask请求处理完成后立即返回页面,彻底解决阻塞问题。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

