PySide6/PyQT多线程之 多线程 与 线程池的模板(拿来即用)

描述

前言

关于PySide6/PyQT多线程系列的最后一篇。写这篇文章的动机是方便后续代码的直接复用。

本篇文章实际是水文,给出了 PySide6/PyQT的多线程以及线程池的基础使用模板,方便后面有需要时候直接拿来就用。


多线程

这里分两种情况来谈论,有返回值 与 无返回值。

无返回值

代码释义

定义 MyThread 的线程类,继承自 QThread
在构造函数中,接收一个函数 func 和其它参数 *args 和 **kwargs
并在 run() 方法中,调用传入的函数,并将参数传递给它。

定义 do_something() 的函数,它表示一个耗时的操作。

在主程序中,实例化MyThread 对象 thread,将 do_something 函数作为参数传递给它。
然后,通过调用 start() 方法启动线程,线程会自动执行 run() 方法中的任务。


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

import time
from PySide6.QtCore import (Qt, QThread)


# 自定义的工作任务类
class MyThread(QThread):
    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)


def do_something():
    time.sleep(100)
    return '耗时操作'


if __name__ == '__main__':
    thread = MyThread(do_something)
    thread.start()

有返回值

有返回值,也分两种情况来讨论

  • 不推荐)使用线程对象的 wait() 方法等待子线程执行完毕,然后通过自定义的方法或属性来获取返回值
  • 推荐) 使用信号和槽机制进行线程间通信

不推荐

这种情况是不推荐的,不够线程安全,
在多线程编程中,共享数据可能存在竞争条件和线程安全性问题,从而引发线程安全性问题。

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

import time
from PySide6.QtCore import (Qt, QThread)


# 自定义的工作任务类
class MyThread(QThread):
    def __init__(self, func, *args, **kwargs):
        super().__init__()
        self.res = str()
        self.func = func
        self.args = args
        self.kwargs = kwargs

    def run(self):
        self.res = self.func(*self.args, **self.kwargs)


def do_something():
    time.sleep(100)
    return '耗时操作'


if __name__ == '__main__':
    thread = MyThread(do_something)
    thread.start()
    thread.wait()
    print(thread.res)

推荐


代码释义

整体流程如下:

  • 创建继承QThreadMyThead类,接收一个函数和不定长传参;重写了 run方法并在这里执行传递过来的函数和传参;
  • 创建继承自 QWidgetMainWindow 类,用于显示窗口和处理事件;
  • setup_ui 方法中设置窗口的标题、大小,并创建标签和按钮,并将它们添加到垂直布局中;
  • setup_thread 方法中创建 MyThread 线程对象,并连接它的 finish 信号到槽函数 thread_finished
  • do_something函数中模拟一个耗时的任务,并返回任务的结果;
  • thread_finished 槽函数中,接收到任务完成的信号后,将结果更新到标签上;
  • 运行程序后,窗口会显示一个标签和一个按钮。点击按钮后,耗时任务会在后台执行,执行完成后,结果会显示在标签上。


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

import time

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


class MyThread(QThread):
    finish = Signal(str)

    def __init__(self, func, *args, **kwargs):
        super().__init__()
        self.func = func
        self.args = args
        self.kwargs = kwargs

    def run(self):
        res = self.func(*self.args, **self.kwargs)
        # 任务完成后发出信号
        self.finish.emit(res)


def do_something():
    time.sleep(1)
    return 'the function execution completed!'


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('execute')
        layout.addWidget(self.button)
        # 将布局设置为主窗口的布局
        self.setLayout(layout)
        # 显示窗口
        self.show()

    def setup_thread(self):
        self.thread = MyThread(do_something)
        self.thread.finish.connect(self.thread_finished)
        self.thread.start()

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


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

线程池

代码释义

MyWorker类继承自QRunnable,接收一个函数、一个信号和其他可变参数。在run方法中,它调用了传入的函数并将结果发射出信号。

do_something函数是一个模拟的耗时操作,它在执行完毕后返回一个字符串。

MainWindow类是窗口的主要部分,它创建了一个垂直布局,并添加了一个标签和一个按钮。点击按钮后,它创建一个MyWorker对象,并使用线程池启动这个线程。同时,它将信号与thread_finished槽函数连接起来,在线程完成后更新标签的文本。

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

import time

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


class MyWorker(QRunnable):

    def __init__(self, func, signal, *args, **kwargs):
        super().__init__()
        self.func = func
        self.args = args
        self.kwargs = kwargs
        self.signal = signal

    def run(self):
        res = self.func(*self.args, **self.kwargs)
        # 任务完成后发出信号
        self.signal.emit(res)


def do_something():
    time.sleep(1)
    return 'the function execution completed!'


class MainWindow(QWidget):
    signal = Signal(str)

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.thread_pool = QThreadPool()
        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('execute')
        layout.addWidget(self.button)
        # 将布局设置为主窗口的布局
        self.setLayout(layout)
        # 显示窗口
        self.show()

    def setup_thread(self):
        worker = MyWorker(do_something, self.signal)
        self.thread_pool.start(worker)
        self.signal.connect(self.thread_finished)

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


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

复用建议

在后续复用中,有以下注意事项

多线程线程池都需要注意的是:

  • run方法中考虑异常捕获;
  • 线程安全性: 在多线程环境下,要注意共享数据的线程安全性。

多线程

  • 线程的生命周期管理: 从创建到销毁的管理。确保在线程执行完毕后,适时释放线程资源,避免线程泄漏或过多的线程资源占用。

线程池

  • 线程池的最大线程数:可以通过修改setMaxThreadCount(n) 来设置线程池的最大线程数。
  • 线程销毁:可以考虑在线程执行完毕后进行销毁操作,以释放资源。可以通过在 MyWorker 的 run 方法中添加 self.setAutoDelete(True) 来实现。

但最重要的是根据实际情况来修改!

后话

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

热烈欢迎CSDN副总裁邹欣老师入驻知识星球

重磅消息 CSDN 副总裁 邹欣 老师成功入驻知识星球 —— 英雄算法联盟,成为合伙人之一。 这将是未来几年内,IT界最震撼的一次合作!我相信就算现在不是,将来必定是! 当然,这对我来说也是一种极大的鼓舞&#…

GPT-5: 超越人类语言的模型,你还不了解一下?

目录 一、GPT-5时代引领者 二、技术特性 1,音频和视频处理 — 更强大的多模态处理能力 2,GPT-5颠覆影视制作:重写媒体消费时代 3,为机器人提供智慧大脑 4,更强的垂直行业应用 三、回顾一下GPT5被紧急叫停&…

AI已经成立社区了,一个个比真人还真

文章目录 nainaimichirper川普的入驻英文版 nainaimi nainaimi是一个13岁的学生,一小时前,被一群人拖到体育馆, 那时的她还很胆小,只能哭诉着那些人的残忍和恶毒 结果半个小时前,她又被拖入了体育馆,这一…

分布式补充技术 01.AOP技术

01.AOP技术是对于面向对象编程(OOP)的补充。是按照OCP原则进行的编写,(ocp是修改模块权限不行,扩充可以) 02.写一个例子: 创建一个新的java项目,在main主启动类中,写如下代码。 package com.co…

基于无人机辅助边缘计算系统的节能卸载策略

源自:《系统工程与电子技术》 作者:余雪勇 朱烨 邱礼翔 朱洪波 摘 要 针对复杂地形中地面基础设施无法有效提供可靠通信和密集算力的问题,首先提出一种基于无人机(unmanned aerial vehicle, UAV)托管计算资源的卸载方案。考虑用户终端的计算需…

西门子PLC如何实现1主多从网口无线通讯

常规来说,多台plc要实现以太网无线连接,首先要先确定以太网线必须正确连接,并建立物理连接。然后需要在PLC端设置好IP地址,以使不同PLC以相同协议可以实现通信交流。最后是建立PLC端数据采集及交换系统,要求在PLC端设置…

直播和短视频美颜sdk的开发流程、代码分析

目前,美颜技术是提高视频质量的重要手段之一,特别是短视频和直播两个行业。本文将介绍其开发流程和代码分析。 一、美颜SDK的开发流程 1.需求分析 首先我们需要明确的一点就是“需求”,例如:美颜效果、美颜程度、性能要求等。同…

【JavaScript】线程和进程,JavaScript线程,事件队列,事件循环 ,微任务、宏任务

❤️ Author: 老九 ☕️ 个人博客:老九的CSDN博客 🙏 个人名言:不可控之事 乐观面对 😍 系列专栏: 文章目录 进程和线程JavaScript线程事件队列、事件循环微任务、宏任务面试题1面试题2 进程和线程 进程&a…

Netty核心技术二--BIO编程

1. I/O模型 I/O 模型简单的理解:就是用什么样的通道进行数据的发送和接收,很大程度上决定了程序通信的性能 Java共支持3种网络编程模型/IO模式:BIO、NIO、AIO Java BIO :同步并阻塞(传统阻塞型),服务器实现模式为一个…

C++13-STL模板

C13-STL模板 在线练习: http://noi.openjudge.cn/ https://www.luogu.com.cn/ 大纲要求 【 3 】算法模板库中的函数:min、max、swap、sort 【 4 】栈 (stack)、队列 (queue)、链表 (list)、 向量(vector)等容器 1.函数模板 泛…

1.2 IAR 环境配置及编译

目录 一. 新建源码文件夹 二. 添加源文件到工程中 三. 编写一个简单的测试程序 四. 设置字体和行号 五. 工程配置 六. 编译链接工程 一. 新建源码文件夹 (1)在保存工作空间和工程的目录下,新建一个code文件夹,用于保存源码&…

突破极限:YOLO9000 论文解读 - 构建更好、更快、更强大的实时检测系统

YOLOv2 论文全篇完整翻译 摘要 我们介绍了YOLO9000,这是一种先进的、实时的目标检测系统,可以检测超过9000个物体类别。首先,我们对YOLO检测方法进行了各种改进,包括新颖的方法和借鉴自先前工作的方法。改进后的模型YOLOv2在标准…

实验四 车辆定位导航

有想自己动手的同学可在末尾看教程 【实验目的】 1、了解全球定位导航系统的定位原理和电子地图技术,掌握电子地图API使用方法。 2、了解导航数据报文数据格式,解析导航数据并在电子地图上进行导航应用。 【实验性质】 验证性实验。 【实验要求】 1、相…

自抗扰PID(梯形图源代码)

有关ADRC的详细算法和源代码,请参看专栏的系列文章,这里不再赘述,常用链接如下: ADRC自抗扰控制算法(含梯形图完整源代码和算法公式)_adrc算法_RXXW_Dor的博客-CSDN博客PLC的自抗扰控制(ADRC)算法_RXXW_Dor的博客-CSDN博客_adrc算法1、自抗扰控制算法,网上很多文章有所…

数据仓库漫谈-前世今生

数据仓库的内容非常多,每一个子模块拎出来都能讲很久。这里没法讲太多细节,大致思考了三个备选议题: 数据仓库的前世今生 数据仓库体系知识介绍 数仓开发者的路在何方? 既然是第一次分享,感觉还是跟大家普及下数仓的…

浏览器数据存储方式

浏览器数据存储方式 常用的前端数据存储方法笼统来说有 3 种: local/session storagecookiesindexeddb 3 种方法各有各的优点和使用范围。 local/session storage local/session storage 保存的格式都为键值对,并且用法都是差不多,如下&…

『树莓派云台机器人』02. 电脑连接树莓派 配置开发环境

目录 1. 下载ssh交互工具 Xshell 与XFTP(有过相关使用经历的朋友可以跳过这一节内容)2. 下载VNC远程控制工具软件3. 连接过程4. Xshell 命令工具5. XFTP 文件传送工具6. 关于联网总结 欢迎关注 『树莓派云台机器人』 博客,持续更新中 欢迎关注…

基于Zynq的雷达10Gbps高速PCIE数据采集卡方案(三)软件设计

4.1 引言 本章基于第二章的分析结论,进行系统软件设计。软件设计包括逻辑设计、嵌入 式软件设计和上位机软件设计。在逻辑设计中,对 ADC 模块、 Aurora 模块、 DDR3 SDRAM 模块和 PCIE 模块进行分析和设计,在 Vivado 软件提供的 …

在 Linux 上使用 yuzu 模拟 Nintendo Switch 试玩王国之泪

王国之泪5月12日发售,DLC 玩家已经造出各种脑洞大开的东西了,但是买的卡带迟迟没有收到,因此,打算使用 yuzu 模拟器先体验一下 yuzu 是一款开源的 Ninetendo Switch 模拟器,支持在 Linux 或者 Windows 平台运行&#…

vue动态class的写法

本文会详细介绍 vue动态 class的写法,并且提供一些我个人的理解,希望对你有所帮助。 如果你是一个新手,或者想了解 vue的源码,那么首先应该学习 vue的基础知识,比如:什么是静态语言,有什么作用等…
最新文章