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

PyQt6 GUI主线程冻结求助:子线程执行任务时界面卡顿

PyQt6主窗口卡顿冻结的问题解决

核心问题定位

你的主窗口冻结是因为子线程的启动方式完全错误,导致繁重任务直接在主线程执行,阻塞了GUI事件循环。错误集中在saveDatabase函数和线程的使用逻辑上。

具体错误点说明

  1. 错误调用run()方法:
    self.thread.started.connect(self.thread.run())这行代码直接在主线程中执行了run(),而不是将其作为线程的执行函数。QThread.start()会自动调用run()方法,不需要手动连接started信号到run()。

  2. 冗余且错误的moveToThread操作:
    self.thread.moveToThread(self.thread)完全没有意义,QThread实例本身就是线程控制器,不需要将它移动到自己的线程中,这属于错误操作。

  3. 进度条最大值计算错误:
    numLinks = self.links.__sizeof__()返回的是列表对象的内存占用大小,不是列表中的元素数量,应该用len(self.links)来获取实际链接数量,否则进度条的范围会完全错误。

  4. 线程未发射finished信号:
    TaskThread的run()方法结束后没有发射finished信号,导致线程结束时无法触发清理逻辑。

修正后的代码

1. 修正saveDatabase函数

def saveDatabase(self):
    # 正确获取链接数量
    numLinks = len(self.links)
    print(numLinks)
    self.progressBar.setRange(0, numLinks)
    
    self.thread = TaskThread(copy.deepcopy(self.links), copy.deepcopy(self.filePathLabel.text()))
    
    # 移除错误的moveToThread调用
    # self.thread.moveToThread(self.thread)
    
    # 移除错误的started连接,start()会自动调用run()
    # self.thread.started.connect(self.thread.run())
    
    self.thread.progress.connect(self.progressBarUp)
    self.thread.finished.connect(self.thread.quit)
    self.thread.finished.connect(self.thread.deleteLater)
    
    self.thread.start()

2. 修正TaskThread类

import os
class TaskThread(QtCore.QThread):
    finished = pyqtSignal()
    progress = pyqtSignal(int)
    
    def __init__(self, links, filePath):
        QtCore.QThread.__init__(self, parent=None)
        self.links = links
        self.filePath = filePath
    
    def run(self):
        # 使用os.path.join拼接路径,避免跨平台问题
        directoryPath = self.filePath
        summaryPath = os.path.join(directoryPath, "summary")
        imagesPath = os.path.join(directoryPath, "images")
        fullPagePath = os.path.join(directoryPath, "fullPage")
        
        # 批量创建目录,加入exist_ok=True避免重复创建报错
        os.makedirs(summaryPath, exist_ok=True)
        os.makedirs(imagesPath, exist_ok=True)
        os.makedirs(fullPagePath, exist_ok=True)
        
        num = 0
        for i in self.links:
            try:
                page = wikipedia.page(i)
                summary = page.summary
                images = page.images
                fullPage = page.content
                
                tempSummaryPath = os.path.join(summaryPath, i)
                tempImagesPath = os.path.join(imagesPath, i)
                tempFullPagePath = os.path.join(fullPagePath, i)
                
                # 写入摘要,指定utf-8编码避免特殊字符报错
                with open(tempSummaryPath, 'w', encoding='utf-8') as f:
                    f.write(summary)
                
                # 可补充写入完整页面内容的逻辑,原代码未处理
                # with open(tempFullPagePath, 'w', encoding='utf-8') as f:
                #     f.write(fullPage)
                
                num += 1
                self.progress.emit(num)
            except Exception as e:
                # 捕获异常避免线程崩溃,可添加日志输出
                print(f"处理链接{i}时出错: {str(e)}")
                num += 1
                self.progress.emit(num)
        
        # 线程结束时发射finished信号
        self.finished.emit()

额外优化建议

  • 禁用按钮防止重复点击:在启动线程时禁用saveFilesButton,线程结束后再启用,避免重复创建线程:
    def saveDatabase(self):
        self.saveFilesButton.setEnabled(False)
        # ...其他代码...
        self.thread.finished.connect(lambda: self.saveFilesButton.setEnabled(True))
    
  • 处理网络请求超时:维基百科请求可能超时,可给wikipedia.page()添加超时参数或重试逻辑。
  • 进度条更新频率优化:如果链接数量极大,可每处理N个链接再发射一次进度信号,减少GUI刷新压力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 00:45:36