PySide6/PyQT多线程之 高效管理多线程:暂停、恢复和停止的最佳实践

news2024/11/20 10:40:27

在这里插入图片描述

前言

关于 PySide6/PyQT 多线程,正确地处理多线程编程并确保线程之间的同步和通信并不容易。
本文以一个示例代码为基础,介绍 PySide6/PyQT多线程的运用,展示如何创建和管理线程,以及如何实现线程之间的同步和通信。

设想这么一个场景:

  • 在实际开发过程中,在涉及到长时间运行的计算任务时,用户可能希望能够暂停、恢复和结束线程的执行,以便更好地控制程序的行为;
  • 如线程间的同步和通信、线程的暂停、恢复和结束等;
  • ...

本专栏前面几篇文章,几乎覆盖了PySide6/PyQT 多线程编程开发中的100%,
PySide6/PyQT中, QProgressBar 控件完美适配了本文的主旨。

于是乎,这篇文章就将前面几篇 PySide6/PyQT 的文章串起来,使用QProgressBar 组件写一个进度条相关的GUI工具,方便读者更加深入的去理解多线程的使用。


值得一提的是,本文的代码是基于下面这篇文章的示例代码。

  • 点击直达PySide6/PyQT多线程之 线程安全:互斥锁&条件变量的最佳实践

知识点📖📖

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

作用链接
创建新线程QThread
对象间通信的机制,允许对象发送和接收信号Signal
用于响应Signal信号的方法Slot
线程同步机制,用于协调多个线程之间对共享资源的访问QMutex
锁定互斥锁的对象,简化代码,避免手动处理锁的加锁和解锁操作QMutexLocker
线程同步机制,一般配合 QMutex 使用QWaitCondition
进度条控件QProgressBar

实现

这里是对完整代码拆解再讲解,

创建线程

  • 重写run()方法,该方法会在新线程启动时候执行;
  • 新增两个方法,分别是暂停和恢复线程
class MyThread(QThread):

    def __init__(self, parent=None):
        super().__init__(parent=parent)

    def pause_thread(self):
        # 在新线程中执行的暂停的代码

    def resume_thread(self):
        # 在新线程中执行的恢复的代码

    def run(self):
		# 在新线程中执行的代码

启动线程

  • 实例化类,再调用 start_thread() 启动线程
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setup_ui()
        self.setup_thread()

    def setup_ui(self):
		# GUI界面绘制

    def setup_thread(self):
        self.thread = MyThread()

    def start_thread(self):
        self.thread.start()

    def paused_thread(self):
        self.thread.pause_thread()

    def resume_thread(self):
        self.thread.resume_thread()
        
    def stop_thread(self):
        self.thread.quit()
my_thread = MyThread()
my_thread
my_thread.start()

暂停线程

  • 调用 pause_thread() 方法,就会暂停线程
self.thread.pause_thread()

恢复线程

  • 调用 resume_thread() 方法,就会恢复线程运行
self.thread.resume_thread()

终止线程

  • 调用 quit() 方法,就会停止线程
self.thread.quit()

完整代码

该代码实现了一个具有启动、暂停、恢复和终止功能的线程,并将进度值显示在进度条上。

# -*- coding: utf-8 -*-
# Name:         demo.py
# Author:       小菜
# Date:         2023/5/4
# Description:

import sys
from PySide6.QtCore import (QThread, QWaitCondition, QMutex, Signal, QMutexLocker)
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QPushButton, QProgressBar, QApplication)


class MyThread(QThread):
    valueChange = Signal(int)

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.is_paused = bool(0)  # 标记线程是否暂停
        self.progress_value = int(0)  # 进度值
        self.mutex = QMutex()  # 互斥锁,用于线程同步
        self.cond = QWaitCondition()  # 等待条件,用于线程暂停和恢复

    def pause_thread(self):
        with QMutexLocker(self.mutex):
            self.is_paused = True  # 设置线程为暂停状态

    def resume_thread(self):
        if self.is_paused:
            with QMutexLocker(self.mutex):
                self.is_paused = False  # 设置线程为非暂停状态
                self.cond.wakeOne()  # 唤醒一个等待的线程

    def run(self):
        while True:
            with QMutexLocker(self.mutex):
                while self.is_paused:
                    self.cond.wait(self.mutex)  # 当线程暂停时,等待条件满足
                if self.progress_value >= 100:
                    self.progress_value = 0
                    return  # 当进度值达到 100 时,重置为 0 并退出线程
                self.progress_value += 1
                self.valueChange.emit(self.progress_value)  # 发送进度值变化信号
                self.msleep(30)


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.thread_running = False  # 标记线程是否正在运行
        self.setup_ui()
        self.setup_thread()

    def setup_ui(self):
        layout = QVBoxLayout(self)
        self.progressBar = QProgressBar(self)
        layout.addWidget(self.progressBar)
        layout.addWidget(QPushButton(r'启动', self, clicked=self.start_thread))
        layout.addWidget(QPushButton(r'停止', self, clicked=self.paused_thread))
        layout.addWidget(QPushButton(r'恢复', self, clicked=self.resume_thread))
        layout.addWidget(QPushButton(r'结束', self, clicked=self.stop_thread))
        self.show()

    def setup_thread(self):
        self.thread = MyThread()
        self.thread.valueChange.connect(self.progressBar.setValue)
        self.thread_running = True

    def start_thread(self):
        if self.thread_running:
            self.thread.start()
        if not self.thread_running:
            self.setup_thread()
            self.thread.start()

    def paused_thread(self):
        if not self.thread_running:
            return
        if not self.thread.isRunning():
            self.thread.start()
        else:
            self.thread.pause_thread()

    def resume_thread(self):
        if not self.thread_running:
            return
        self.thread.resume_thread()

    def stop_thread(self):
        self.thread.quit()  # 终止线程的事件循环
        self.thread_running = False  # 标记线程停止
        self.progressBar.setValue(0)  # 重置进度条的值


if __name__ == '__main__':
    app = QApplication()
    window = MainWindow()
    sys.exit(app.exec())

代码释义

MyThread 类

MyThread类继承自QThread,是一个自定义的线程类。它通过发射信号来通知界面更新进度条的值。

属性

  • valueChange:自定义的信号,用于发送进度值变化的信号。
  • is_paused:一个布尔值,用于标记线程是否暂停。
  • progress_value:一个整数,表示进度值。
  • mutex:QMutex对象,用于线程同步。
  • cond:QWaitCondition对象,用于线程暂停和恢复。

方法

  • __init__(self, parent=None):构造函数,用于初始化对象。
  • pause_thread(self):暂停线程的方法。
  • resume_thread(self):恢复线程的方法。
  • run(self):线程执行的方法。在一个无限循环中,判断线程是否暂停,如果是则等待件满足;否则,增加进度值,并发射进度值变化的信号。
  • msleep(self, milliseconds):线程休眠的方法,以毫秒为单位。

MainWindow类

MainWindow 类是一个继承自 QWidget 的窗口类。它包含了一些状态变量和方法来管理线程和界面的交互。

属性

  • thread_running:一个布尔值,标记线程是否正在运行

方法

  • setup_ui:设置用户界面。创建一个垂直布局,并在布局中添加了一个进度条 QProgressBar 和四个按钮 QPushButton。这些按钮分别是 “启动”、“停止”、“恢复” 和 “结束”。
  • setup_thread:设置线程。实例化一个 MyThread 对象,并将进度值变化的信号 valueChange 与进度条的 setValue 方法连接起来。在线程运行时,进度条的值会随着信号的发出而更新。同时将 thread_running 标志设置为 True,表示线程正在运行。
  • start_thread:启动线程。如果 thread_running 为 True,表示线程已经存在,直接调用 start 方法来启动线程。如果 thread_running 为 False,则调用 setup_thread 方法来创建并设置线程,然后再启动线程。
  • paused_thread:用于暂停线程。如果线程没有运行,即 isRunning() 返回 False,则调用 start 方法来启动线程。否则,调用线程的 pause_thread 方法来暂停线程的执行。
  • resume_thread:用于恢复线程的执行。如果线程没有运行,即 thread_running 为 False,则直接返回。否则,调用线程的 resume_thread 方法来恢复线程的执行。
  • stop_thread:用于停止线程。它调用线程的 quit 方法来终止线程的事件循环,并将 thread_running 标志设置为 False,表示线程已停止。同时,将进度条的值重置为 0

运行结果

在这里插入图片描述

总结🎈🎈

本文中,展示了使用 PySide6/PyQT实现多线程编程,实现了一个具有启动、暂停、恢复和终止功能的线程。

本文虽然是一个简单的示例,但它也将PySide6/PyQT多线程开发中该用到的知识点都用上了,算是抛砖引玉吧。希望本文能够帮助读者理解和应用 PySide6 的多线程功能。

后话

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

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

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

相关文章

IP组播路由协议(组播内部网关协议)

IP组播路由协议:用来建立组播树,是实现组播传输的关键技术。分为源分发树和共享分发树。 PIM:协议无关组播 密集模式: PIM-DM:密集模式PIM DVMRP:距离矢量组播路由协议 MOSPF:组播开放式最短链路优先 稀疏模式 CBT:基于核心的树 PIM-SM:稀疏模式PIM 这…

微星UEFI签名密钥泄露引发“末日”供应链攻击恐慌

对硬件制造商微星Micro-Star International(更广为人知的名称是 MSI)的勒索软件入侵引发了人们对毁灭性供应链攻击的担忧,这些攻击可能会注入恶意更新,这些更新已使用受大量最终用户设备信任的公司签名密钥进行签名。 这有点像世…

chatgpt赋能Python-python3_7怎么更新

Python3.7如何更新? 对于拥有10年Python编程经验的工程师来说,更新Python版本是必不可少的。现在最新版本的Python是3.7,那么这个版本应该如何更新呢? 更新步骤 下载Python3.7安装包 在Python官网上下载即可。如果你使用的是L…

Cube Map 系列之:手把手教你 实现 立方体贴图

什么是Cube Map 在开始立方体贴图之前,我们先简单了解下cube map。 cube map 包含了六个纹理,分别表示了立方体的六个面; 相较二维的纹理使用坐标uv来获取纹理信息,这里我们需要使用三维的方向向量来获取纹理信息(一…

力扣---LeetCode20. 有效的括号(栈)

文章目录 前言🌟一、20. 有效的括号🌟二、链接🌟三、方法:栈实现🌏3.1思路:🌏3.2代码: 🌟四、补充:😽总结 前言 👧个人主页&#xff1…

springboot+java高校教师学术成果管理系统-idea

功能介绍项目介绍Spring框架是Java平台的一个开放源代码的Full-stack(全栈)应用程序框架,和控制翻转容器的实现。Spring框架的一些核心功能理论,可以用于所有Java应用,Spring还为Java EE构建的Web应用提供大量的扩展支持。Spring框架没有实现…

python使用基础 pycharm代码的git同步

我们大家在编写代码的时候经常会遇到各种版本的控制问题。为此版本控制工具是每一个编写代码的同志均需要面临的问题。目前,业内已经有非常成熟的解决方案,比如我们常说的github、gitee等。由于国内网络原因,本文以gitee为例进行使用说明。 1…

基于SpringCloud的分布式网上商城的设计与实现

背景 经过网上调查和搜集数据,我们可以发现商城管理方面的系统并不是相当普及,在分布式架构商城管理方面的可以有许多改进。实际上如今信息化成为一个未来的趋势或者可以说在当前现代化的城市典范中,信息化已经成为主流,开发一个分布式架构网上商城系统一方面的可能会更合乎时…

chatgpt赋能Python-python3_7怎么安装pil

如何在Python3.7中安装PIL? Python3.7是一种流行的编程语言,广泛应用于机器学习、Web开发、数据科学等领域。PIL(Python Imaging Library)是一种Python图像处理库,它提供了丰富的图像处理功能,能够对图像进行缩放、旋转、裁剪等操…

chatgpt赋能Python-python3_8怎么调成黑色背景

如何将Python3.8调整为黑色背景 Python是一种高级编程语言,常用于开发Web应用程序和科学计算。Python3.8是其最新的版本,随着其市场份额的增加,越来越多的程序员对其进行学习和使用。对于那些想要使他们的编程环境更加现代化和个性化的程序员…

060:cesium设置网格Grid材质

第060个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中设置网格材质,请参考源代码,了解GridMaterialProperty的应用。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共93行)相关API参考:专栏目标示例效…

挂机宝搭建教程

nokvm主控面板推荐操作系统版本 Centos7.6.1810 (纯净的操作系统,无其他软件环境) 主控面板硬件要求配置: - 最低要求 推荐配置 内存 2G 2G CPU - - 带宽 不低于2M 2M 磁盘 / 分区不少于100GB 100GB 主控面板安装&#xff1…

关于shrio的动态授权

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、关于表的搭建1.表介绍二、配置shiroFilterFactoryBean 的权限访问三、配置doGetAuthorizationInfo的授权信息前言 其实一开始的写过一次关于shrio的动态授权但是那个是单表实现的不是特别完…

chatgpt赋能Python-python3_9_1怎么安装

Python 3.9.1 安装指南 介绍 Python是一种高级编程语言,具有简洁、易读、易学、可扩展等特点。它是一种面向对象的编程语言,支持多种编程范式,如面向过程编程、函数式编程、面向对象编程等,也支持各种不同的编程领域&#xff0c…

26-jQuery-概述和下载使用

一、什么是 jQuery? jQuery 是一款流行的 JavaScript 框架,被广泛应用于 Web 开发中。它简化了 DOM 操作、事件处理、动画效果等常见任务,提供了丰富的 API 和插件,让开发者能够快速地实现各种功能。jQuery设计的宗旨是"wri…

6G 第六代移动通信和sub6G第五代移动通信的中低频段

“ 6G:第六代移动通信,概念被炒得火热,却一直不冷不热, 受限于功率和传输距离等,很难落地。” “ sub6G:第五代移动通信的中低频段,虽然已部署了很多, 却受限于功耗、成本、杀手级…

使用Keras构建分类问题的MLP神经网络——用于糖尿病预测

大家好,我是带我去滑雪! Keras 是一个用于构建和训练深度学习模型的高级 API,它基于 Python编写,并能够运行于 TensorFlow, CNTK, 或者 Theano 等深度学习框架之上。Keras简化了深度神经网络的构建流程,让用户能够更加…

基于Springboot的漫画网站

开发技术介绍 B/S架构 B/S结构是目前使用最多的结构模式,它可以使得系统的开发更加的简单,好操作,而且还可以对其进行维护。使用该结构时只需要在计算机中安装数据库,和一些很常用的浏览器就可以了。浏览器就会与数据库进行信息…

chatgpt赋能Python-python3_7_2怎么安装

Python 3.7.2 安装指南 Python 是一种广泛使用的计算机编程语言,在科学计算、数据处理、网络编程、人工智能等领域都有广泛应用。而 Python 3.7.2 是 Python 3 系列的一个重要版本。在本文中,我们将介绍如何在各种操作系统上安装 Python 3.7.2。 安装步…

chatgpt赋能Python-python3_8降到3_7

Python 3.8降级到3.7:这是否是一个明智的决策? Python 3.8是Python语言的最新版本,拥有许多显著的改进和新功能。然而,许多开发者们发现3.8版本并非适用于每个项目,因此他们可能会想要降级回Python 3.7。本文将探讨降…