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

如何在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))

关键修改点:

  1. target=downloader:传递函数本身,而非立即执行函数
  2. args=(h,):以元组形式传递函数参数(注意末尾逗号,避免被解析为单个变量)
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 22:30:31