首页 > 解决方案 > PySide2 中的 QThread 已启动,但未在启动信号上触发插槽

问题描述

编辑:我使变量更具描述性,添加了触发线程的按钮,更改了问题描述

通过单击按钮启动给定线程后的预期行为:

我实际得到的是:

按预期工作线程 1,但对于线程 2 和 3

这个例子所基于的基本问题可以用一个 QThread 而不是三个来解决,但寻求帮助的主要目的和主题是了解我需要做些什么才能使这个特定的例子在三个线程的情况下工作以及为什么它不是按预期在 Windows 10 下工作(在 Linux 下我得到了预期的结果以及在 Windows 10 下的 PyCharm 中的调试模式)。

只是猜测:是线程优先级问题吗?问题与给定线程的事件循环或工作者所有权有关吗?您是否有任何与我的问题相关的有用文章?

from PySide2 import QtCore, QtWidgets
from PySide2.QtWidgets import QApplication


class Worker(QtCore.QObject):
    some_action_1_thread_finished = QtCore.Signal()
    some_action_2_thread_finished = QtCore.Signal()
    some_action_3_thread_finished = QtCore.Signal()

    def __init__(self):
        super().__init__()
        self.flag = None

    QtCore.Slot()
    def make_some_action_1(self):
        self.flag = 0
        print(f'I am in make_some_action_1')
        print(f'action 1 : {self}')
        self.some_action_1_thread_finished.emit()

    QtCore.Slot()
    def make_some_action_2(self):
        # time.sleep(10)
        self.flag = 20.1
        print(f'I am in make_some_action_2')
        print(f'action 2 : {self}')
        self.some_action_2_thread_finished.emit()

    QtCore.Slot()
    def make_some_action_3(self):
        # time.sleep(5)
        self.flag = 101.3
        print(f'I am in make_some_action_3')
        print(f'action 3 : {self}')
        self.some_action_3_thread_finished.emit()

    def __repr__(self):
        return f'{self.flag}'


class Controller(QtCore.QObject):
    def __init__(self):
        super().__init__()
        self.worker = Worker()

        self.some_action_1_thread = QtCore.QThread()
        self.worker.moveToThread(self.some_action_1_thread) # should be moved to the specific method ran during thread triggering
        print(':: checkpoint 1')
        self.some_action_2_thread = QtCore.QThread()
        # self.worker.moveToThread(self.some_action_2_thread)
        print(':: checkpoint 2')
        self.some_action_3_thread = QtCore.QThread()
        # self.worker.moveToThread(self.some_action_3_thread)
        print(':: checkpoint 3')

        self.main_window = MainWindow()
        self.main_window.show()

        self.worker.some_action_1_thread_finished.connect(self.some_action_1_thread.quit)
        self.worker.some_action_1_thread_finished.connect(self.on_finished_1)
        self.some_action_1_thread.started.connect(self.worker.make_some_action_1)
        print(':: checkpoint A')
        self.worker.some_action_2_thread_finished.connect(self.some_action_2_thread.quit)
        self.worker.some_action_2_thread_finished.connect(self.on_finished_2)
        self.some_action_2_thread.started.connect(self.worker.make_some_action_2)
        print(':: checkpoint B')
        self.worker.some_action_3_thread_finished.connect(self.some_action_3_thread.quit)
        self.worker.some_action_3_thread_finished.connect(self.on_finished_3)
        self.some_action_3_thread.started.connect(self.worker.make_some_action_3)
        print(':: checkpoint C')
        self.main_window.exit_button.clicked.connect(self.main_window.close)
        self.main_window.thread_1_button.clicked.connect(self.on_thread_1_button)
        self.main_window.thread_2_button.clicked.connect(self.on_thread_2_button)
        self.main_window.thread_3_button.clicked.connect(self.on_thread_3_button)

    def trigger_thread_1(self):
        self.some_action_1_thread.start()
        print('thread 1 started')
        # self.some_action_2_thread.start()
        # self.some_action_3_thread.start()
        # time.sleep(10)

    def trigger_thread_2(self):
        self.some_action_2_thread.start()
        print('thread 2 started')

    def trigger_thread_3(self):
        self.some_action_3_thread.start()
        print('thread 3 started')

    def on_finished_1(self):
        print('FINISHED, stopping thread 1')

    def on_finished_2(self):
        print('FINISHED, stopping thread 2')
        # self.trigger_thread_3()

    def on_finished_3(self):
        print('FINISHED, stopping thread 3')

    def on_thread_1_button(self):
        self.trigger_thread_1()

    def on_thread_2_button(self):
        self.trigger_thread_2()

    def on_thread_3_button(self):
        self.trigger_thread_3()


class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.exit_button = QtWidgets.QPushButton('Exit')
        self.thread_1_button = QtWidgets.QPushButton('Thread 1')
        self.thread_2_button = QtWidgets.QPushButton('Thread 2')
        self.thread_3_button = QtWidgets.QPushButton('Thread 3')

        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.exit_button)
        self.layout.addWidget(self.thread_1_button)
        self.layout.addWidget(self.thread_2_button)
        self.layout.addWidget(self.thread_3_button)
        self.setLayout(self.layout)



if __name__ == '__main__':

    app = QApplication([])

    controller = Controller()

    print(f'MAIN Process: worker flag : {controller.worker}')
    app.exec_()
    print(f'After event loop: worker flag : {controller.worker}')
    print('END')

编辑 2

使它工作的解决方案似乎是:

def trigger_thread_X(self):
    self.worker.moveToThread(self.some_action_X_thread)
    # ...
def make_some_action_X(self):
    # ...
    self.moveToThread(app.thread())

标签: pythonmultithreadingpyside2qthread

解决方案


推荐阅读