欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

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组件,使用其他线程操作组件很有可能会出现莫名的闪退,需要在其他线程操作组件时可使用信号-槽的方式进行操作。