PySide6/PyQT多线程之 线程池的基础概念和最佳实践

news2024/12/29 9:11:30

在这里插入图片描述

前言

PySide6/PyQT 多线程编程中,线程池也是重要的一项知识点,线程池是一种高效管理和调度多个线程执行任务的方式。
通过结合线程池(QThreadPool)和任务类(QRunnable),可以轻松地实现并发执行任务、提高应用程序的性能,并更好地控制代码逻辑和资源的管理。

值得注意的是,在使用 QRunnableQThreadPool 的线程池中,每个任务(QRunnable 对象)会被分配到不同的线程执行,每个线程拥有自己的任务和局部数据。因此,默认情况下,每个任务在自己的线程中是相互独立的,不会直接共享资源。

知识点📖📖

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

作用链接
对象间通信的机制,允许对象发送和接收信号Signal
用于响应Signal信号的方法Slot
可运行的任务类,用于封装要在后台线程中执行的代码逻辑QRunnable
线程池类,用于管理和调度多个线程执行 QRunnable 任务QThreadPool

基础概念

QRunnable

一个接口类,用于表示可以在线程中执行的任务。通过继承 QRunnable 并实现 run 方法,可以定义任务的逻辑。

QThreadPool

一个管理线程的线程池类。它可以管理和执行 QRunnable 对象,并自动管理线程的创建、回收和重用。

QThreadPool 可以限制并发线程的数量,防止资源过度占用。

QRunnable 更适合用于执行短期、轻量级的任务,而 QThread 更适合用于需要更多控制和状态管理的长期任务。

使用 QRunnableQThreadPool 的优势在于线程的创建和管理交由线程池处理,可以避免频繁创建和销毁线程,提高效率,并根据系统资源和任务数量自动调整线程的数量。



创建线程池步骤

创建自定义任务类(QRunnable

  • 创建继承自 QRunnable 的自定义任务类。在任务类中实现 run() 方法,该方法包含要在后台线程中执行的代码逻辑。
class Worker(QRunnable):
    def __init__(self, func, *args, **kwargs):
        super().__init__()
        self.func = func
        self.args = args
        self.kwargs = kwargs

    def run(self):
        # 执行任务函数,并传递参数
        self.func(*self.args, **self.kwargs)

创建线程池对象(QThreadPool

  • 在应用程序中创建一个线程池对象。通过直接实例化 QThreadPool 或使用 QThreadPool.globalInstance() 方法获取全局线程池实例。
def main():
    # 创建线程池对象
    threadpool = QThreadPool()

创建任务对象并提交给线程池

  • 创建一个任务对象,将其实例化为自定义任务类的实例。
  • (可选)可以通过构造函数传递任务所需的函数、参数或其他数据。
  • 使用线程池的 start() 方法将任务对象提交给线程池执行。
# 示例任务函数
def task_func():
    # 耗时操作
   
# 创建任务对象并提交给线程池
task1 = Worker(task_func, "John")
threadpool.start(task1)

task2 = Worker(task_func, "Alice")
threadpool.start(task2)

与QThread相比较

优势有挺多的,参考如下:

  • 将任务的执行和线程管理分离,使代码更具可维护性和可扩展;
  • 管理和控制多个任务的并发执行,以最大程度地利用系统资源;
  • 在需要执行大量独立任务或耗时操作的情况下,提供一种高效的并发处理方式;
  • 提高应用程序的响应性,通过并行执行任务,减少主线程的负载,避免阻塞用户界面;
  • 通过将任务逻辑封装在 QRunnable 中,并使用 QThreadPool 进行任务的调度和管理,轻松实现多线程应用程序,提高性能和响应性,并且更好地控制和组织代码。
  • 自动管理线程的创建、回收和重用,避免频繁创建和销毁线程,从而减少了线程切换和资源消耗。线程池可以重用线程,避免了重复创建线程的开销。

总结

综上所述,使用 QRunnable 和 QThreadPool 相对于直接使用 QThread 提供了更高级的线程管理功能、更好的性能优化、更好的并发控制和更好的可扩展性。

它通过自动管理线程的创建和回收、动态调整线程数量、限制并发线程的数量等机制,减少了线程切换和资源消耗,提高了整体系统性能和稳定性。

同时,将任务逻辑封装在 QRunnable 中,使代码更清晰和可维护,并提供了更灵活的任务管理方式。

常用方法

threadpool = QThreadPool()

常用的方法列举在这里,

代码释义
start(QRunnable)将一个任务(QRunnable 对象)提交给线程池执行
activeThreadCount()返回当前正在执行任务的线程数
maxThreadCount()返回线程池允许的最大线程数
waitForDone(msecs = -1)等待线程池中的所有任务执行完成,或者等待指定的毫秒数。如果设置为 -1,则会一直等待直到所有任务完成
clear()清除线程池中所有待执行的任务,但不会停止正在执行的任务

代码展示

这只是一份简单的线程池模板,没啥用~

import time
from PySide6.QtCore import (QRunnable, QThreadPool, Qt)



# 自定义的工作任务类
class Worker(QRunnable):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print(f"Worker {self.name} started")
        time.sleep(2)  # 模拟一些耗时的工作
        print(f"Worker {self.name} finished")


def main():
    # 创建线程池
    thread_pool = QThreadPool()

    # 设置最大线程数
    thread_pool.setMaxThreadCount(4)

    # 创建工作任务并将其添加到线程池
    for i in range(1, 6):
        worker = Worker(f"Task {i}")
        thread_pool.start(worker)

    # 在等待所有任务完成之前,阻塞主线程
    thread_pool.waitForDone()
    print("All tasks completed")


if __name__ == "__main__":
    main()

代码释义

  1. 定义工作任务类:定义了一个名为Worker的自定义类,它继承自QRunnable类。这个类表示一个工作任务,具体的工作逻辑定义在run方法中。

  2. Worker类的__init__方法:这个方法用于初始化工作任务对象。在这个示例中,将每个工作任务命名为name,并将其保存在self.name属性中。

  3. Worker类的run方法:这个方法表示工作任务的执行逻辑。在示例中,打印工作任务的名称,然后使用time.sleep方法模拟一些耗时的工作(2秒),最后再次打印工作任务的名称。

  4. main函数:程序的入口点。在这个函数中执行以下操作:

    • 创建线程池:使用QThreadPool()创建一个全局的线程池对象thread_pool
    • 设置最大线程数:使用setMaxThreadCount方法设置线程池的最大线程数为4。
    • 创建工作任务并添加到线程池:使用一个循环创建了5个工作任务,每个任务都有一个唯一的名称。然后,使用start方法将这些工作任务添加到线程池中,以便并行执行。
    • 阻塞主线程直到任务完成:使用waitForDone方法阻塞主线程,直到所有任务完成执行。
    • 打印所有任务完成的消息:在所有任务完成后,打印"All tasks completed"的消息。

这份代码创建了一个线程池并将多个工作任务添加到线程池中执行。
每个任务都是通过继承QRunnable类并实现run方法来定义的。通过使用线程池,这些工作任务可以在多个线程中并行执行,从而提高程序的效率。
最后,等待所有任务完成后,打印出任务完成的消息。

总结🎈🎈

本文介绍了PySide6/PyQT线程池的基本概念和使用方法。介绍了QRunnableQThreadPool的作用,以及它们结合在一起的优势。

通过使用QRunnableQThreadPool,可以将任务的执行和线程管理分离,提高应用程序的性能和响应性。

我建议常见的多线程场景都用上线程池,省事~

后话

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

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

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

相关文章

【分布族谱】正态分布和卡方分布的关系

文章目录 正态分布卡方分布卡方分布的极限 正态分布 正态分布,最早由棣莫弗在二项分布的渐近公式中得到,而真正奠定其地位的,应是高斯对测量误差的研究,故而又称Gauss分布。。测量是人类定量认识自然界的基础,测量误差…

FFmpeg命令实战(上)

标题 1.FFmpeg命令行环境搭建2.ffmpeg,ffplay和ffprobe的区别3.ffmpeg处理流程4.ffmpeg命令分类查询5.ffplay播放控制6.ffplay命令选项 1.FFmpeg命令行环境搭建 1.到达FFmpeg的github,选择下载需要的版本,这里以windows举例。 这里有两个压缩包,ffmpeg-master-lat…

Flutter 笔记 | Flutter Native 插件开发 (Android)

oh, 我亲爱的朋友,很高兴你来到了这里!既然来了,那么就让我们在这篇糟糕的烂文章中,一起来学习一下,如何在一个糟糕的 Flutter 混合应用中开发一个糟糕的 Android Native 烂插件吧!😑 首先&…

研报精选230519

目录 【行业230519头豹研究院】2023年中国产后康复设备行业词条报告 【行业230519山西证券】有色金属行业周报:锂价快速回升,释放锂电行业复苏信号 【行业230519头豹研究院】2023年中国氢能重卡行业词条报告 【个股230519西南证券_森麒麟】腾飞的高端轮胎…

网页外包开发的测试方法及工具

网页开发的软件项目完成代码开发后需要进行全面的测试,这是正规的软件公司开发软件项目必须要做的工作,这方面有不少好用的工具供大家使用。今天和大家分享这方面的知识,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件…

Elasticsearch实战之处理邮件附件进行进行内容全文检索

目录 一、系统环境和软件要求 二、软件说明 三、定义文本抽取管道(pipeline) 四、建立索引设置文档结构映射 五、插入文档 六、查询文档 需求是将本地邮件内容以及PDF,EXCEL,WORD等附件内容进行处理,保存到ES数据库,实现邮件…

【I2C 通信的工作原理是什么?Arduino 和 I2C 教程】

【I2C 通信的工作原理是什么?Arduino 和 I2C 教程】 1. 概述2. I2C 的工作原理3. I2C 协议4. 例程5. Arduino I2C 代码在本教程中,我们将了解 I2C 通信协议的工作原理,我们还将使用 Arduino 板和使用该协议的传感器制作一个实际示例。您可以观看以下视频或阅读下面的书面教程…

chatgpt赋能Python-python3虚拟环境搭建

Python3虚拟环境搭建:介绍和步骤 Python是一门非常强大的编程语言,因此在许多不同类型的项目中都广泛使用。但是,不同项目可能需要使用不同版本的Python库和依赖项。这就是使用Python的虚拟环境的重要性,可以避免不同项目之间的冲…

「实验记录」MIT 6.824 Raft Lab2B Log Replication

#Lab2B - Log Replication I. SourceII. My CodeIII. MotivationIV. SolutionS1 - leader上任即初始化S2 - leader发送AppendEntriesS3 - follower接收AppendEntriesS4 - leader收到AppendEntries 回信S5 - candidate选举限制S6 - defs.go约定俗成和实现Start() V. Result I. S…

yolov7结构改进策略解析

论文链接:https://arxiv.org/abs/2207.02696 代码链接:https://github.com/WongKinYiu/yolov7 具体分割如何训练,请参考我之前的博客论文: https://blog.csdn.net/qq_41920323/article/details/129464115?spm1001.2014.3001.5502…

联用多个插件可以让 GPT-4 的能力更加强大,实现更加复杂的操作

🚀 联用多个插件可以让 GPT-4 的能力更加强大,实现更加复杂的操作。 联用多个插件可以让 GPT-4 的能力更加强大,实现更加复杂的操作。 不过,使用插件和联网功能也有一些要注意的地方。 首先是安全性问题,特别是像购…

Burpsuite模块—-Intruder模块详解

一、简介 Burp Intruder是一个强大的工具,用于自动对Web应用程序自定义的攻击,Burp Intruder 是高度可配置的,并被用来在广范围内进行自动化攻击。你可以使用 Burp Intruder 方便地执行许多任务,包括枚举标识符,获取有…

Kali-linux密码在线破解

为了使用户能成功登录到目标系统,所以需要获取一个正确的密码。在Kali中,在线破解密码的工具很多,其中最常用的两款分别是Hydra和Medusa。本节将介绍使用Hydra和Medusa工具实现密码在线破解。 8.1.1 Hydra工具 Hydra是一个相当强大的暴力密…

浅谈分布式事物解决方案

目录 背景 1 XA规范分布式事物方案 1.1 俩阶段提交(2PC) 1.2 三阶段提交(3PC) 2 补偿事务(TCC) 3 可靠消息最终一致性方案 4 可靠消息最终一致性方案 5 SAGA事物 6 Seata AT 模式 背景 分布式事务出现…

使用Git-lfs上传超过100m的大文件到GitHub

文章目录 1. 安装 git-lfs2. 在Git中安装git-ifs3. 找到工程中的所有大文件4.执行完这行命令,项目目录下会生成文件 .gitattributes,此时Git push将 .gitattributes 提交到远程仓库。 5. 需要注意的事 1. 安装 git-lfs Git Large File Storage | Git La…

Day44【动态规划】完全背包、518.零钱兑换 II、377.组合总和 Ⅳ

完全背包 文章讲解 视频讲解 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将物品装入背包里的最大价值 完全背包和01背包问题…

F103ZET6使用FSMC和HAL点亮ILI9341

前言 将标准库下的ILI9341驱动移植到使用CubeMX生成的HAL库环境,并成功运行。 一、STM32CubeMX生成框架 (一)配置RCC、SYS和时钟树 参见常规配置。 (二)配置FSMC 1、原理图引脚定义 LCD8080接口使用的引脚主要分…

【数据结构】线性表 ⑤ ( 双循环链表 | 双循环链表特点 | 双循环链表插入操作处理 | 代码示例 - 使用 Java 实现 双循环链表 )

文章目录 一、双循环链表二、双循环链表特点三、双循环链表插入操作处理四、代码示例 - 使用 Java 实现 双循环链表 一、双循环链表 " 双循环链表 " 是 在 单循环链表 的基础上 , 在每个 节点 中 , 新增一个 指针 , 指向 该节点 的 前驱节点 ; 双向循环链表 每个 节…

头歌计算机组成原理实验—运算器设计(8)第8关:乘法流水线设计

第8关:乘法流水线设计 实验目的 学生掌握运算流水线基本概念,理解将复杂运算步骤细分成子过程的思想,能够实现简单的乘法运算流水线。 视频讲解 实验内容 在 Logisim 中打开 alu.circ 文件,在6位补码阵列乘法器中利用5位阵列乘…

React学习笔记三-模块与组件的理解

此文章是本人在学习React的时候,写下的学习笔记,在此纪录和分享。此为第三篇,主要介绍react中的模块与组件。 目录 1.模块与组件 1.1模块 1.2组件 1.3模块化 1.4组件化 2.React面向组件编程 2.1函数式组件 2.2类组件 2.2.1类知识的复…