wd1566 2025-08-10 17:58 采纳率: 100%
浏览 11
已结题

PyQt5中,创建了线程为什么还会阻塞主程序

我创建了一个长时的工作类,并在主线程中实例化,然后再实例化一个QThread对象, 将工作对象加进去,最后起动线程,为什么还是会使主界面无响应呢?

工作类

class Worker(QObject):
    progress_updated = pyqtSignal(int, str)  # (进度百分比, 状态消息)
    # result = pyqtSignal(str)  # 结果信号
    finished = pyqtSignal(bool, str)  # 完成信号

    def __init__(self, parent=None):
        super().__init__(parent)
        self._is_running = False

    def cancel(self):
        self._is_running = False

    def do_cycles(self, con, groups: List[Group], total_seconds, total_cycles) -> None:
        begin_time = int(time.time())
        self._is_running = True
        try:
            # 开始总的循环
            for c in range(total_cycles):
                if not self._is_running:
                    break
                # 开始group的遍历
                for g in range(len(groups)):
                    if not self._is_running:
                        break
                    group = groups[g]
                    print(f"g={g}")
                    print(f"groupid:{group.id}")
                    # 开始对单个组内的命令执行循环
                    for s in range(group.cycles):
                        if not self._is_running:
                            break
                        # 遍历组内命令
                        for i in range(len(group.sequences)):
                            if not self._is_running:
                                break
                            seq = group.sequences[i]
                            # self.label_status.setText(f"当前执行第{c + 1}次循环, 第{g + 1}组的第{s + 1}次循环,当前第{i + 1}步。")
                            # self.label_status.update()
                            # self.label_status.repaint()
                            SwitchCommand.send_operation(con, seq.switch, seq.operation)
                            start_time = int(time.time())
                            time.sleep(1)
                            while int(time.time()) - start_time < seq.duration:
                                if not self._is_running:
                                    break
                                progress = int(((int(time.time())-begin_time) / total_seconds) * 100)
                                status = f"当前执行第{c + 1}次循环, 第{g + 1}组的第{s + 1}次循环,当前第{i + 1}步。"
                                self.progress_updated.emit(progress, status)
                                time.sleep(1)  # 每隔1s检查是否达到驻留时间值。
            if self._is_running:
                self.finished.emit(True, "程序运行结束!")
        except Exception as e:
            self.finished.emit(False, f"程序运行失败!{str(e)}")
        finally:
            self._is_running = False

主程序中实现类:


```python
"""初始化工作线程"""
        self.thread = QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.thread)

        # 连接信号
        self.worker.progress_updated.connect(self.update_progress)
        # self.worker.result.connect(self.show_result)
        self.worker.finished.connect(self.handle_task_completion)
        self.thread.started.connect(lambda: self.worker.do_cycles(self.con, self.group_list, self.total_second, self.total_cycles))


按钮事件中开启线程:
 self.thread.start()

```

  • 写回答

5条回答 默认 最新

  • 码农阿豪@新空间 新星创作者: 前端开发技术领域 2025-08-10 18:05
    关注
    让阿豪来帮你解答,本回答参考chatgpt3.5编写提供,如果还有疑问可以评论或留言
    在主界面中,如果在主线程中进行重度的计算操作或者长时间的操作,会导致主界面无响应,因为主界面是负责界面刷新和事件处理的,如果有耗时操作或者占用大量计算资源,会导致主界面无法及时响应用户操作。 在你的代码中,你将工作类Worker的实例放在了主线程中,并且使用了QThread来执行这个Worker的do_cycles方法。但是由于do_cycles方法中的循环操作比较繁重,包括了等待时间的操作(time.sleep)和界面更新操作(self.progress_updated.emit),这些操作都在QThread中进行,会造成主界面的无响应情况。 为了避免这种情况,应该让耗时的操作在子线程中执行,而界面更新操作在主线程中执行。可以使用QObject的moveToThread方法将Worker对象移到子线程中,并且在子线程中执行耗时的操作,然后通过信号和槽机制将结果传递回主线程进行界面更新。 下面是修改后的代码示例:
    class Worker(QObject):
        progress_updated = pyqtSignal(int, str)
        finished = pyqtSignal(bool, str)
        def __init__(self, parent=None):
            super().__init__(parent)
            self._is_running = False
        def cancel(self):
            self._is_running = False
        def do_cycles(self, con, groups: List[Group], total_seconds, total_cycles):
            # 在子线程中执行耗时的操作,比如循环操作等
            pass
    # 主程序中实现类
    class MainClass(QMainWindow):
        def __init__(self):
            super().__init__()
            self.thread = QThread()
            self.worker = Worker()
            self.worker.moveToThread(self.thread)
            self.worker.progress_updated.connect(self.update_progress)
            self.worker.finished.connect(self.handle_task_completion)
            self.thread.started.connect(lambda: self.worker.do_cycles(self.con, self.group_list, self.total_second, self.total_cycles))
        def start_thread(self):
            self.thread.start()
        def update_progress(self, progress, status):
            # 在主线程中更新界面
            pass
        def handle_task_completion(self, success, message):
            # 在主线程中处理任务完成的信号
            pass
    

    在这个修改后的代码中,do_cycles方法中的耗时操作在子线程中执行,将结果通过信号progress_updated和finished传递到主线程中更新界面和处理任务完成的情况。这样可以避免主界面无响应的情况。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

问题事件

  • 系统已结题 8月29日
  • 已采纳回答 8月21日
  • 创建了问题 8月10日