python - PySide2 中的 QThread 已启动,但未在启动信号上触发插槽
问题描述
编辑:我使变量更具描述性,添加了触发线程的按钮,更改了问题描述
通过单击按钮启动给定线程后的预期行为:
- 线程 X 被触发并启动
- -> worker.make_some_action_X
- -> worker.some_action_X_thread_finished发出信号
- -> controller.on_finished_X被调用。
我实际得到的是:
按预期工作线程 1,但对于线程 2 和 3:
- 线程 2(线程 3)被触发并启动,但不再执行,
- 它们被冻结/挂起,直到我再次运行线程 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:
使它工作的解决方案似乎是:
worker
在线程 X 被触发时移动到给定的线程 X
def trigger_thread_X(self):
self.worker.moveToThread(self.some_action_X_thread)
# ...
- 在 some_action 完成后移
worker
回主线程:
def make_some_action_X(self):
# ...
self.moveToThread(app.thread())
解决方案
推荐阅读
- php - SQL Pivot Query 中的 PHP 数组显示不同的数据
- c# - 对其他进程进行强制收集和压缩有用的情况
- google-analytics - 如何在谷歌分析推荐部分显示名称?
- javascript - 如何将对象的对象数组转换为一维数组?
- python - 从 imblearn.combine 导入 SMOTEENN 时,ImportError 是:“无法导入名称 get_max_squared_sum”
- docker - 将命令从 docker 容器暴露到主 shell
- python - 从打印的心电图中提取图形
- java - 如果参数是同一接口的不同实现, compareTo() 应该返回什么?
- xamarin.android - 我无法在 Xamarin.android 项目中安装 FM.IceLink.WebRTC
- android - 检查片段中的 savedInstanceState 状态