长任务反馈:daemon 线程 + 信号 vs 直接阻塞的取舍
长任务,界面不能卡
识一个目录要好几秒。如果你在按钮回调里直接同步跑,界面就彻底卡死,用户以为程序死了。
第一性原理:长时间任务必须离开 UI 线程,用后台线程跑,然后靠信号把进度/结果送回来更新界面。
两种 vi 思路
做法一:直接阻塞(错)
python
def _on_click(self):
self.split_btn.setEnabled(False)
heavy_work(self.pdf) # 阻塞UI好几秒,界面死给你看
self.split_btn.setEnabled(True)
界面在这几秒里无法响应、无法重绘,体验极差。
做法二:daemon 线程 + 信号(对)
python
def _run_split(self):
...
threading.Thread(target=self._split_worker, daemon=True).start()
def _split_worker(self):
result = step_split(self._pdf, self._plugin, temp_dir)
self.split_done.emit(result) # 信号回到主线程
后台线程算,算完 emit 信号,主线程在 connect 的槽里更新界面、恢复按钮。
daemon=True 的意义
daemon=True 表示这是守护线程:主程序退出时它自动被拖死,不会阻塞程序关闭。
python
threading.Thread(target=self._split_worker, daemon=True).start()
对我们的场景,任务跑不完程序要退出,直接放弃即可,不用等它------这正合适。
取舍结论
- 直接阻塞:禁止,UI 卡死。
- daemon + 信号:UI 顺畅,退出无牵挂,结果靠信号回主线程更新。
别每次看按钮回调里放一堆重活,一律走"后台线程跑 + 信号回主线程"。这条天花板,PySide6 项目尤其重要。