PySide主窗口弹出QInputDialog时工作线程中断,如何让线程独立运行?
问题修复方案
核心原因
模态弹窗阻塞子线程的问题,通常是三个常见原因导致的:
- Python标准库的
time.sleep受GIL调度影响,主线程处理UI模态事件时可能会临时挂起子线程的sleep调度,看起来就像子线程停止运行 - 若实际业务中Worker线程用到了Qt信号槽、定时器等依赖事件循环的组件,没有开启子线程自身的事件循环会导致这些组件在主线程阻塞时无法正常工作
- (如果用到跨线程信号交互)错误使用
Qt.BlockingQueuedConnection类型的信号连接,会让子线程等待主线程处理完信号再继续执行,主线程被弹窗阻塞时子线程也会跟着卡住
修复代码
from PySide6.QtCore import QThread, Qt from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QInputDialog import sys class Worker(QThread): def __init__(self): super().__init__() # 不需要线程随主窗口销毁自动终止可以注释下面这行 self.finished.connect(self.deleteLater) def run(self): for i in range(0,100): # 替换time.sleep为Qt自带的sleep方法,不受GIL调度优先级影响 self.sleep(2) print(i) # 如果Worker需要用到信号槽、QTimer等组件,注释上面的循环,加下面这行开启子线程事件循环 # self.exec() class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.button = QPushButton(parent=self) self.setCentralWidget(self.button) self.button.setText("BUTTON") self.button.clicked.connect(self.button_clicked) self.worker = Worker() self.worker.start() def button_clicked(self): text, ok = QInputDialog.getText(self, 'input', 'input') if ok: # 此处不要做耗时操作,避免阻塞主线程 pass # 主窗口关闭时安全终止子线程,避免异常退出 def closeEvent(self, event): if self.worker.isRunning(): self.worker.quit() self.worker.wait() event.accept() if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec())
额外注意事项
- 不要在子线程中操作任何UI组件,所有UI更新都要通过信号槽发送到主线程处理
- 跨线程信号连接使用默认的
Qt.AutoConnection即可,不要手动指定为Qt.BlockingQueuedConnection,避免子线程被主线程阻塞 - Worker实例必须绑定到主窗口的成员属性(即
self.worker),避免被Python垃圾回收意外销毁,导致线程异常终止
内容的提问来源于stack exchange,提问作者datacast
相关产品推荐
相关产品推荐

