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

如何通过QButton终止concurrent.future中的线程任务

解决concurrent.futures线程无法终止的问题

原代码存在的问题

  1. 使用with ThreadPoolExecutor会在Start_Button_clicked函数执行完毕后自动关闭线程池,导致后续无法通过线程池控制任务。
  2. 错误调用Future对象的shutdown方法——shutdown是ThreadPoolExecutor的方法,而非Future对象的方法。
  3. 任务函数task_work未检查停止信号,即使修改Stop_Work变量,任务仍会继续执行。
  4. 普通全局布尔变量作为停止信号存在线程安全隐患,且Qt主线程中调用time.sleep(1)会导致UI卡顿。

解决方案

  1. 用threading.Event作为线程安全的停止信号,替代全局布尔变量。
  2. 将ThreadPoolExecutor设为类成员变量,避免with语句自动关闭线程池,保留控制权。
  3. 在task_work循环中检查停止信号,触发后立即终止任务。
  4. 控制按钮状态防止重复提交任务,移除主线程中的阻塞操作。

修正后的完整代码

import time
import threading
from concurrent.futures import ThreadPoolExecutor

from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton


class MyApp(QMainWindow):
    def __init__(self):
        super().__init__()
        # 窗口设置
        self.setWindowTitle("线程控制示例")
        self.setFixedSize(228, 150)

        # 线程安全的停止信号
        self.stop_event = threading.Event()
        # 线程池实例(类成员)
        self.executor = None
        self.future = None

        # 按钮初始化
        self.start_btn = QPushButton("Start", self)
        self.start_btn.setGeometry(25, 20, 178, 41)
        self.start_btn.clicked.connect(self.on_start_clicked)

        self.stop_btn = QPushButton("Stop", self)
        self.stop_btn.setGeometry(25, 89, 178, 41)
        self.stop_btn.clicked.connect(self.on_stop_clicked)
        self.stop_btn.setEnabled(False)

    def on_start_clicked(self):
        print("开始按钮被点击")
        # 重置停止信号(允许任务运行)
        self.stop_event.set()
        # 初始化线程池
        self.executor = ThreadPoolExecutor(max_workers=2)
        # 提交任务
        self.future = self.executor.submit(self.task_work)
        # 更新按钮状态
        self.start_btn.setEnabled(False)
        self.stop_btn.setEnabled(True)

    def on_stop_clicked(self):
        print("停止按钮被点击")
        # 触发停止信号
        self.stop_event.clear()
        # 取消未执行任务并关闭线程池
        if self.executor:
            self.executor.shutdown(wait=False, cancel_futures=True)
        # 更新按钮状态
        self.start_btn.setEnabled(True)
        self.stop_btn.setEnabled(False)

    def task_work(self):
        try:
            i = 0
            for _ in range(10):
                i += 1
                print(f"I: {i}")
                # 检查停止信号,触发则终止任务
                if not self.stop_event.is_set():
                    print("任务被终止")
                    break
                # 模拟任务耗时
                time.sleep(2.5)
            else:
                print("任务正常完成")
        finally:
            # 确保线程池资源释放
            if self.executor:
                self.executor.shutdown(wait=False)

if __name__ == '__main__':
    app = QApplication([])
    window = MyApp()
    window.show()
    app.exec()

关键修改说明

  • 线程安全信号:threading.Event()通过set()/clear()/is_set()实现线程间安全的状态交互,避免全局变量的线程冲突。
  • 线程池控制权:将线程池设为类成员,保留对其的控制能力,可在停止时主动调用shutdown取消任务。
  • 任务内终止逻辑:在task_work的循环中实时检查停止信号,确保触发停止后任务能立即退出。
  • UI状态优化:通过按钮禁用/启用防止重复操作,移除主线程中的sleep避免UI卡顿。

内容的提问来源于stack exchange,提问作者韩云涛

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 12:29:52