Qt 多线程(pyside6)
最编程
2024-05-22 22:52:04
...
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
qt多线程使用
- 正确食用方法
- 线程启动及停止
- 实际应用
- QT大坑总结
-
- 线程提前结束
- slot函数会跑在主线程上
- QPlainTextEdit clear后append或其他操作会导致应用崩溃
- 不要使用非主线程来操作ui组件
正确食用方法
网上很多都是创建一个新类继承自QThread,但是查阅了一些资料和博客,官方推荐的是新类继承QObject,然后新实例化一个QThread对象,再通过moveToThread方法将对象转移至新线程中
# 实例化需要多线程直接方法的类,里面包含执行方法
worker_obj = Obj()
# 实例化QThread,开启一个新线程对象
worker_thread = QThread()
# 将执行方法的类的线程指向转移至新的线程对象
worker_obj.moveToThread(worker_thread)
线程启动及停止
# 通过信号发起对应的动作
# 操作类的动作信号绑定操作方法
worker_obj.todo_signal.connect(todo)
# 线程开始时,绑定操作类中的工作信号
worker_thread.started.connect(worker_obj.todo_signal)
# 线程退出时,调用deleteLater删除对象
worker_thread.finished.connect(worker_obj.deleteLater)
worker_thread.finished.connect(worker_thread.deleteLater)
# 通过start方法启动线程
worker_thread.start()
# 通过quit方法停止线程
worker_thread.quit()
实际应用
# 线程锁
lock = QMutex()
# 操作类
class TaskWorker(QObject):
# 操作信号
send_task_signal = Signal(dict)
# 初始化时传入相关数据参数及线程对象
def __init__(self, db, element, label_element, submit_element, task_args, task_type, thread, parent=None) -> None:
super(TaskWorker, self).__init__(parent)
self.db = db
self.element = element
self.label_element = label_element
self.task_args = task_args
self.task_type = task_type
self.submit_element = submit_element
self.thread = thread
# 执行方法,启锁、关锁、执行动作、退出线程
def start_task(self):
lock.lock()
send_label_job({"db": self.db, "element": self.element, "label_element": self.label_element, "task_args": self.task_args, "task_type": self.task_type})
self.submit_element.setEnabled(True)
lock.unlock()
self.thread.quit()
# 实例化线程对象
self.task_worker_thread = QThread()
# 实例化操作类
self.task_worker = TaskWorker(db, self.dataResultPlainTextEdit, self.label_task_id, self.createTaskButton, task_args, self.task_type, self.task_worker_thread)
# 将操作类线程指向转移到新线程对象
self.task_worker.moveToThread(self.task_worker_thread)
# 将线程started信号绑定到操作类执行方法
self.task_worker_thread.started.connect(self.task_worker.start_task)
# 线程退出销毁对象
self.task_worker_thread.finished.connect(self.task_worker.deleteLater)
self.task_worker_thread.finished.connect(self.task_worker_thread.deleteLater)
# 线程开始
self.task_worker_thread.start()
QT大坑总结
线程提前结束
QThread:Destroyed while thread is still running
出现这个报错,注意看下线程对象及操作类对象是不是局部变量,如果是局部变量,当所在方法执行完成时就会销毁所有局部变量则会出现这报错。可以将变量转换为global全局变量或self实例变量,让其持久化。这个大坑因为菜卡了很久,特此记下以便以后查阅。
slot函数会跑在主线程上
多线程时,耗时操作别用信号连接槽函数方式执行,使用信号-槽方式,多线程中只有started信号连接的函数会跑在新线程里,自定义信号连接的函数将会跑在主线程上!!!
# 如下面task_worker中的signal在start_task方法中执行时,signal emit执行会在新线程中,但是signal connect的方法执行时会在main线程里
self.task_worker_thread.started.connect(self.task_worker.start_task)
QPlainTextEdit clear后append或其他操作会导致应用崩溃
如果result = ‘’ 注释掉,应用大概率会崩溃,在QPlainTextEdit 元素clear后插入其他操作,在进行元素操作则不会崩溃,感觉这个应该是QT的BUG,这个BUG太过折磨人了基本无从发现。
element.clear()
result = ''
element.appendPlainText('请求发送中,请稍等……')
不要使用非主线程来操作ui组件
qt的主线程叫做界面线程,可以用界面线程操作所有ui组件,使用其他线程操作组件很有可能会出现莫名的闪退,需要在其他线程操作组件时可使用信号-槽的方式进行操作。