在独立类中定义Qt信号用于QRunnable worker时信号重复接收
问题分析与解决
问题根源
你代码里的Worker类把signals定义成了类属性,所有Worker实例会共享同一个Signals对象。每次调用enqueue时,都会给这个共享的complete信号新增一个到WorkerManager.complete槽的连接。
比如创建2个worker时:
- 第一个worker入队,信号被连接1次
- 第二个worker入队,信号又被连接1次
此时信号总共被连接了2次,所以每个worker发射信号时,槽函数都会被触发2次,最终输出4条记录;3个worker的话就是3次连接,每个发射触发3次,总共9条记录。
修复方案
把signals从类属性改成实例属性,让每个Worker实例拥有独立的Signals对象,这样每个信号只会被连接一次。
修改Worker类的代码:
class Worker(QRunnable): def __init__(self): super().__init__() self.worker_id = uuid.uuid4().time_mid # 将signals改为实例属性,每个worker拥有独立的信号对象 self.signals = Signals() def run(self): time.sleep(0.01) self.signals.complete.emit(self.worker_id)
修复后完整代码
import time, uuid from qtpy.QtCore import QObject, QThreadPool, QRunnable, Signal from qtpy.QtWidgets import QApplication, QMainWindow, QPushButton class MainWindow(QMainWindow): def __init__(self): super().__init__() self.button = QPushButton("Start 2 workers") self.button.pressed.connect(self.start) self.setCentralWidget(self.button) self.worker_manager = WorkerManager() def start(self): for i in range(2): worker = Worker() self.worker_manager.enqueue(worker) class Signals(QObject): complete = Signal(int) class Worker(QRunnable): def __init__(self): super().__init__() self.worker_id = uuid.uuid4().time_mid self.signals = Signals() def run(self): time.sleep(0.01) self.signals.complete.emit(self.worker_id) class WorkerManager(QObject): def __init__(self): super().__init__() self.threadpool = QThreadPool() def enqueue(self, worker): worker.signals.complete.connect(self.complete) self.threadpool.start(worker) def complete(self, worker_id): print('complete:', worker_id) def main(): app = QApplication([]) window = MainWindow() window.show() app.exec() if __name__ == '__main__': main()
验证效果
运行修改后的代码,点击按钮创建2个worker,输出会变成:
complete: xxxxx complete: yyyyy
每个worker的完成信号只会被接收一次,符合预期。
内容的提问来源于stack exchange,提问作者mins
相关产品推荐
相关产品推荐

