PySide6/PyQT多线程之 编程入门指南:基础概念和最佳实践

news2024/10/3 2:16:12

在这里插入图片描述

前言

本篇文章介绍 PySide6/PyQT多线程编程的基本概念,用到的知识点,以及PySide6/PyQT多线程的基本使用。

看多线程介绍,就看 知识点📖📖

看多线程代码,就看 实现


知识点📖📖

本文用到的几个PySide6的知识点及链接。

作用链接
创建新线程QThread
对象间通信的机制,允许对象发送和接收信号Signal
用于响应Signal信号的方法Slot
互斥锁,用于保护对象QMutex
QMutex一起使用QWaitCondition

多线程模块

值得注意的是在 PySide6/PyQT 中实现多线程,可以选择的有很多,有 QObject、QThread、QRunnable、QThreadPool 等;

  • 其中QThread是继承了QObject 的类,它可以作为基类来创建自定义的线程类;
  • QThreadPool 是一个线程池类,它管理着一组线程,可以方便地调度和管理线程的执行;
  • QRunnable 是一个任务接口,用于将任务封装为一个可在后台线程中执行的对象。可以通过继承 QRunnable 类来实现自定义的任务,并在 QThreadPool 中执行。

多线程通信和同步

在多线程的编程中,线程之间的通信和同步是绕不开的话题。

通信:

  • PySide6/PyQT 提供了信号槽(Signal and Slot) 机制,它们用于在线程之间传递消息和触发事件。通过在不同的线程中发送信号和连接槽函数,可以实现线程间的通信。

同步:

  • 在共享对象被多个线程同时访问时候容易出现意料之外的问题,需要保护好资源争夺;
  • 互斥锁(QMutex)和条件变量(QWaitCondition)等同步机制可以用于控制线程的并发访问,确保线程安全和避免线程竞争。

多线程异常

这个较为通俗易懂,一般来说 使用 try-except 去捕获线程内部可能发生的异常,并在 except 语句块中处理异常即可。

异常处理:

  • 在捕获到异常后,可以选择重新尝试操作、回退到安全状态、释放资源、打印错误信息等。

当然,也可以在异常时候 使用signal信号发送异常的消息。(示例代码如下

from PySide6.QtCore import QThread, Signal

class MyThread(QThread):
    # 定义一个线程崩溃的信号
    thread_crashed = Signal(Exception)

    def run(self):
        try:
            # 线程的执行逻辑
            pass
        except Exception as e:
            # 发送线程崩溃的信号
            self.thread_crashed.emit(e)

多线程生命周期

线程的生命周期包括:线程的创建、启动、运行、暂停、恢复和终止等阶段。

在使用多线程时候,需要注意多线程的生命周期。因为合理管理线程的生命周期可以避免线程资源的浪费和泄漏。

  • 如果是使用QThread,则需要手动处理这些操作,否则可能会导致资源泄漏或线程的未正常退出。

  • 如果是使用 QRunnbale + QThreadPool,主线程则会根据线程池的设置自动创建和销毁线程,从而减少了手动管理线程的复杂性。

所以我推荐使用 QRunnbale + QThreadPool,因为省事~~


多线程优先级

线程优先级决定了线程在竞争CPU资源时的执行顺序,优先级越高的线程在竞争CPU时会被更早地执行。

当然,这个线程优先级并不一定保证绝对的执行顺序,只是优先级越高的在竞争CPU时候,会有更高的概率更早执行;因为线程优先级的具体表现会受到系统的调度算法和资源情况的影响。


多线程应用场景

如果你看了这篇文章,那么大概你已经有了 多线程的应用场景了。

大致搜罗了下,应用场景如下:

  1. 后台下载文件、图像处理,数据处理等 避免阻塞主线程,提升处理的性能和用户体验。
  2. 网络请求网络通信等;
  3. 多任务并发执行;
  4. 反正一句话!就是避免阻塞主线程并提高效率!!!

实现

QThread 多线程

使用注意事项

在使用 PySide6QThread 时,注意事项包括且不局限于以下几点:

  • 不要使用Python原生的线程库来实现;
  • 消息或任务结果 通过Signal信号来传递;
  • 不要在QThread调用主线程的GUI控件应用程序会进入卡死状态;
  • QThread对象必须在主线程中创建,否则程序可能会奔溃;
    • 因为PySide6是基于事件循环的框架,GUI线程子线程都运行在同一个事件循环中。如果在子线程中创建和启动QThread对象,它会尝试创建一个新的事件循环,这会导致两个事件循环并行运行,产生无法预估的结果。

代码

代码用上一篇文章中的,看这里 —《解决PySide6/PyQT的界面卡死问题(PySide6/PyQT多线程》

# -*- coding: utf-8 -*-

import time

import requests

from PySide6.QtCore import (QThread, Signal, Slot, QSize)
from PySide6.QtWidgets import (QApplication, QPushButton, QLabel, QVBoxLayout, QWidget)


class MyThread(QThread):
    signal_tuple = Signal(tuple)

    def __init__(self, func, *args, **kwargs):
        super().__init__()
        self.func = func
        self.args = args
        self.count: int = kwargs.get('count')

    def run(self):
        for idx in range(1, self.count + 1):
            result = self.func(*self.args)
            time.sleep(1)
            # 任务完成后发出信号
            self.signal_tuple.emit((idx, result))


class MainWindow(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setup_ui()
        #
        self.button.clicked.connect(self.setup_thread)

    def setup_ui(self):
        self.setWindowTitle('demo')
        self.resize(QSize(250, 180))
        # 创建一个垂直布局
        layout = QVBoxLayout()
        # 创建一个标签
        self.label = QLabel('This is a label => ')
        layout.addWidget(self.label)
        # 创建一个按钮
        self.button = QPushButton('Send Request')
        layout.addWidget(self.button)
        # 将布局设置为主窗口的布局
        self.setLayout(layout)
        # 显示窗口
        self.show()

    def setup_thread(self):
        self.thread_ = MyThread(self.send_request,
                                count=10)
        self.thread_.signal_tuple.connect(self.thread_finished)
        self.thread_.start()

    def send_request(self):
        return requests.get('https://www.csdn.net/').text[:15]

    @Slot(tuple)
    def thread_finished(self, item):
        self.label.setText('This is a label => ' + str(item))


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

代码释义


MyTherad类

  • 继承了QThread
  • 创建了一个 signal_tuple信号;
  • 类接收一个func函数以及不定长的传参(这里主要传funccount
  • 重写 run方法,线程的 start() 方法被调用时,就会自动执行run方法;
  • 执行 count 次数的func,每次睡眠1秒,使用signal_tuple 将执行结果和执行次数发送出去。

MainWindow类

  • 继承了 QWidget,实现了包含一个按钮和一个标签的简单窗口;
  • setup_thread 函数中,实例化了MyThread,并将实例化后的signal_tuple信号连接到 thread_finished函数;
  • thread_finished为槽函数,当signal_tuple发出信号时,这Slot(槽函数)将被调用,并修改label 的显示。

在实例代码 以及 代码释义中可以清晰的看到,示例代码完美符合了本文中我指出来的 QThread 多线程的几个注意事项:

  • 使用Signal信号传递运行结果;
  • 在主线程中创新子线程;
  • 不在子线程中修改主线程的控件。

以上便是 QThread 多线程PySide6/PyQT 中的简单使用。


后话

本次分享到此结束,
see you~~🐱‍🏍🐱‍🏍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/484421.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《手腕光电容积图智能手表对房颤检测的录制长度和其他心律失常的影响》阅读笔记

目录 一、论文摘要 二、论文十问 三、论文亮点与不足之处 四、与其他研究的比较 五、实际应用与影响 六、个人思考与启示 参考文献 一、论文摘要 本研究旨在评估手腕光电容积图(PPG)的定量分析是否能检测到房颤(AF)。使用心…

项目管理-计算专题(挣值分析)

挣值分析法 是对项目进行跟踪与预测的方法;项目有良好的任务细分以及合理的日程安排;不牵涉到复杂的数学计算;在软件项目管理中,一般以一周为单位定期进行。 项目案例 有一个砌墙项目,需要完成一堵长度为100米的围墙…

第二十四章 纹理贴图

通常情况下,3D网格模型只能展示游戏对象的几何形状,而表面的细节则纹理贴图提供。纹理贴图通过UV坐标“贴附”在模型的表面。当然,这个过程不需要我们在Unity中完成,而是在建模软件中完成的。通常情况下,我们通过3ds m…

基于matlab使用合成雷达和无线通信信号训练的语义分割神经网络执行频谱检测

一、前言 此示例展示了如何使用使用合成雷达和无线通信信号训练的语义分割神经网络执行频谱检测。经过训练的神经网络可以识别出现在相同接收频谱中的雷达和无线通信信号。此外,网络可以识别接收信号的占用带宽。 二、介绍 由于对更高速度和更大覆盖范围的需求不断增…

多元时间序列 | BP神经网络多变量时间序列预测(Matlab完整程序)

多元时间序列 | BP神经网络多变量时间序列预测(Matlab完整程序) 目录 多元时间序列 | BP神经网络多变量时间序列预测(Matlab完整程序)预测结果评价指标基本介绍程序设计参考资料预测结果 评价指标 训练集数据的R2为:0.99805 测试集数据的R2为:0.98351 训练集数据的MAE为:…

小黑子—Java从入门到入土过程:第八章

Java零基础入门8.0 Java系列第八章1. 双列集合 Map1.1 Map 集合中常见的API1.2 Map 集合的遍历方式1.2 - I 第一种遍历方式:键找值KeySet 方法1.2 - II 第二种遍历方式:键值对 entrySet 方法1.2 - III 第三种遍历方式:lambda表达式 1.3 HashM…

沁恒 CH32V208(三): CH32V208 Ubuntu22.04 Makefile VSCode环境配置

目录 沁恒 CH32V208(一): CH32V208WBU6 评估板上手报告和Win10环境配置沁恒 CH32V208(二): CH32V208的储存结构, 启动模式和时钟沁恒 CH32V208(三): CH32V208 Ubuntu22.04 Makefile VSCode环境配置 硬件部分 CH32V208WBU6 评估板WCH-LinkE 或 WCH-Link 硬件环境与Windows下…

【51单片机】数码管显示(样例展示以及异常分析)

🎊专栏【51单片机】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【如愿】 大一同学小吉,欢迎并且感谢大家指出我的问题🥰 ⭐数码管 比如要显示“6”,那么下面图片中,AFEDCG=1,B=0 对应到数码管上,就是 ⭐原理 🎊P22~P24控制LED1~

玩转ChatGPT:吴恩达/OpenAI合作教程《面向开发者的ChatGPT提示工程》

一、写在前面 最近,吴恩达与CloseOpenAI合作出了一个教程《面向开发者的ChatGPT提示工程》,第一时间就观摩了,有些体会,现在把个人觉得有意思的搬运过来。 我的机器学习入门就是看的吴恩达的教程!大佬长得像冯巩&…

解决Element-UI清空表单及验证不生效的问题

问题描述 由于我将编辑与新增时,表单使用的是同一个data中的数据,这就导致出现了我点击了编辑后,再次点击新增时,出现了数据依旧是刚才编辑表单中的数据。 解决办法 尝试一(不推荐) 通过手动给表单中的…

【五一创作】版本控制-从零开始学Git-01什么是Git

一、版本控制 1.1 概念 什么是"版本控制"?版本控制就是一种记录一个或多个文件内容变化、以便开发者 或者其他用户将来对特定版本的文件进行查阅、备份、恢复等操作的系统,即版本控制系统。(VCS,version control system)。 1.2 为何需要版本…

15-4-线程-线程同步之互斥量加锁解锁

一、概念 互斥量:互斥量(mutex)从本质上来说是一把锁,在访问共享资源前对加互斥量(实现加锁),在访问完成后释放互斥量(实现解锁)。 加锁后,任何其他试图再次…

SpringMvc拦截器使用介绍

文章目录 拦截器拦截器基本介绍拦截器快速入门拦截器参数 拦截器 拦截器基本介绍 拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行 作用: 在指定的方法调用前后执行预先设定的代码 阻…

详解MySQL索引

目录 1.什么是索引 2.使用索引的优缺点 3.索引的数据结构 4.索引的分类 5.索引的操作 6.复合索引的数据结构 1.什么是索引 当我们想在一本书里面找到具体的章节的时候,最快的办法是去查看这本书的目录,索引就类似于数据库中存储的数据的目录&…

LeetCode-1033. 移动石子直到连续

题目链接 LeetCode-1033. 移动石子直到连续 题目描述 题解 题解一(Java) 作者:仲景 这题目挺难懂的,得画画图才能更好的理解 这也是LeetCode的尿性,习惯了,非得整这种别人看不懂的鸟语 你可以这样理解&a…

总结839

每日必复习:(微习惯,5分钟) 回顾了第二讲数列极限,明天加大回顾力度,复习才是王道。 学习内容: 暴力英语:艾玛沃特森在联合关于女性平等的演讲,背诵并默写了前四段&…

windows/linux文件传输

windows系统下文件传输-FTP python安装pyftpdlib模块 pip install pyftpdlib 这里可能会出现报错,自己看着更换源解决 然后运行python,在2121端口监听 python -m pyftpdlib 然后我们可以使用windows命令行进行操作,自己可以去看下相关文…

Linux配置静态IP地址

个人PC访问虚拟机的基本原理: PC借助虚拟网卡访问虚拟机(VMWare)的网关,再通过网关连接虚拟机。因此,PC的虚拟网卡,虚拟机的网关,虚拟机,三者的IP地址应在同一网段。(默…

【方法】如何在PPT文稿中插入Word表格?

我们在做PPT文稿的时候,经常需要导入其他文档的内容,比如想在PPT里插入Word表格,要怎么操作呢?方法很容易,来看看下面的具体操作步骤吧。 首先,打开PPT后,点击菜单【插入】列表中的【对象】。 …

nodejs+vue+java农村信息化服务平台

用户的登录模块:用户登录本系统,对个人的信息等进行查询,操作可使用的功能。 用户注册模块:游客用户可以进行用户注册,系统会反馈是否注册成功。 添加管理员模块:向本系统中添加更多的管理人员,…