PySide6学习专栏(四):用多线程完成复杂计算任务

如果计程序中要处理一个非常庞大的数据集中的数据,且数据处理计算很复杂,造成数据处理占用大量时间和CPU资源,如果不用多线程,仅在主进程中来处理数据,将会使整个程序卡死,必须采用多线程来处理这些数据是唯一的选择,下面分别给出几种多线程的使用方法供参考:

1、示例1:一采用基于PySide6的多线程(比PYTHON自带的多线程类要好用的多)来处理大数据的示例:

程序运行界面如下:

# -*- coding: utf-8 -*-
#模块功能:演示多线程类calcuteThread及其子类trdCalcute_01、trdCalcute_02....等来执行多线程数据计算,
#         用于将大量复杂的数据计算包装到多线程类中来完成
#         ID=1 ID=2两个线程演示多线程同主窗口数据通信,ID=3 ID=4演示用继承多线程基类calcuteThread
#         的子类trdCalcute_01、trdCalcute_02。。。来将大量复杂的数据分块后分别交由不同线程完成计算任务
#         一个线程类可初始化多个对象,对相同计算功能的可用一个同名线程类定义多个实例化线程对象,
#         每个线程对象执行相同的计算功能完成对拆分的大数据分块计算,不同计算功能的可分别继承定义不同功能的线程子类并实例化对象

import sys,os,time,math,copy,random
from math import * 
import PySide6
from PySide6 import *
from PySide6.QtCore  import *
#from PySide6.QtGui  import *
from PySide6.QtWidgets  import *
from PySide6.QtWidgets import (QApplication, QFrame, QHBoxLayout, QLabel,
    QLayout, QMainWindow, QMenu, QMenuBar,
    QPushButton, QSizePolicy, QStatusBar, QToolBar,
    QVBoxLayout, QWidget)
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
    QMetaObject, QObject, QPoint, QRect,
    QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
    QCursor, QFont, QFontDatabase, QGradient,QMovie,
    QIcon, QImage, QKeySequence, QLinearGradient,
    QPainter, QPalette, QPixmap, QRadialGradient,
    QTransform)

import math         #此方法导入库,引用库中函数时,需加上模块前缀math.
from math import *  #此方法导入库,引入库中函数时,无需加上模块前缀math
import numpy as np  #此方法导入库,因采用了

MAX_THREAD_NUM=100   #最大允许可同时开的多线程数量

#基于PySide6的演示窗口类
class MainWindow(QWidget):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle('多线程(同时开4个)示例')
        self.resize(900,500)
        #仅示例,实际数据集可能几百万个,可设置干个线程,每个线程分别处理计算数据集中的某一段数据即可,最后将处理后的计算结果全并即完成任务
        self.lstDatas=[0,1,2,3,4,5,6,7,8,9]           #交由多线程(ID=3线程)计算处理的数据集合(可为字典,列表,np结构等,一般采用内存共享处理方式,多线程计算完成后,不必在主进程再对数据处理了)
        self.npDatas=np.array([0,1,2,3,4,5,6,7,8,9])  #交由多线程(ID=4线程)计算处理的np数据集合
        self.startTime3=self.endTime3=0.0  
        self.endTime4=self.endTime4=0.0 
        layout = QFormLayout()   
        self.pushButton_1 = QPushButton()
        self.pushButton_1.setText("开始新线程1(calcuteThread基类)")
        self.pushButton_2 = QPushButton()
        self.pushButton_2.setText("开始新线程2(calcuteThread基类)")
        self.pushButton_3 = QPushButton()
        self.pushButton_3.setText("开始线程3(calcuteThread的trdCalcute_01子类")
        self.pushButton_4 = QPushButton()
        self.pushButton_4.setText("停止线程1")
        self.pushButton_5 = QPushButton()
        self.pushButton_5.setText("停止线程2")
        self.pushButton_6 = QPushButton()
        self.pushButton_6.setText("停止线程3")
        self.pushButton_7 = QPushButton()
        self.pushButton_7.setText("开始线程4(calcuteThread的trdCalcute_01子类)")
        self.pushButton_8 = QPushButton()
        self.pushButton_8.setText("停止线程4")

        self.edita1 = QLineEdit()
        self.edita1.setText('信号槽:线程1的值')
        self.progressBar_1=QProgressBar()
        self.progressBar_1.setMinimum(0)
        self.progressBar_1.setMaximum(100)
        self.edita2 = QLineEdit()
        self.edita2.setText('信号槽:线程2的值')
        self.progressBar_2=QProgressBar()
        self.progressBar_2.setMinimum(0)
        self.progressBar_2.setMaximum(100)
        self.edita3 = QLineEdit()
        self.edita3.setText('信号槽:线程3的值')
        self.edita4 = QLineEdit()
        self.edita4.setText('信号槽:线程4的值')

        layout.addRow("单击按纽开始线程1(线程sleep 10毫秒)->",self.pushButton_1)
        layout.addRow("单击按纽结束线程1->",self.pushButton_4)
        layout.addRow("信号槽方式返回线程1的值->",self.edita1)
        layout.addRow("线程1返回值(进度条展示)->",self.progressBar_1)
        layout.addRow("单击按纽开始线程2(线程sleep 50毫秒)->",self.pushButton_2)
        layout.addRow("单击按纽结束线程2->",self.pushButton_5)
        layout.addRow("信号槽方式返回线程2的值->",self.edita2)
        layout.addRow("线程2返回值(进度条展示)->",self.progressBar_2)
        layout.addRow("单击按纽开始线程3(计算处理list数据集中的0-4段)->",self.pushButton_3)
        layout.addRow("单击按纽结束线程3->",self.pushButton_6)
        layout.addRow("信号槽方式返回线程3对list数据集(0-4段)计算处理结果->",self.edita3)
        layout.addRow("单击按纽开始线程4(计算处理np数据集中的5-9段)->",self.pushButton_7)
        layout.addRow("单击按纽结束线程4->",self.pushButton_8)
        layout.addRow("信号槽方式返回线程4对np数据集(5-9段)计算处理结果->",self.edita4)      
        
        self.setLayout(layout)
        self.pushButton_4.setEnabled(False)
        self.pushButton_5.setEnabled(False)
        self.pushButton_6.setEnabled(False)
        self.pushButton_8.setEnabled(False)

        #定义线程数组字典(相当于字典的key=线程ID号,字典的value=线程类的实例化对象)
        self.dicThread={}                                      #增加的线程数量不大于AX_THREAD_NUM,每增加一个线程,字典会相应增加线程变量
        self.bthreadopen=np.full((MAX_THREAD_NUM),False)       #定义线程打开的状况
        self.pushButton_1.clicked.connect(self.start_worker_1)
        self.pushButton_2.clicked.connect(self.start_worker_2)
        self.pushButton_3.clicked.connect(self.start_worker_3)
        self.pushButton_4.clicked.connect(self.stop_worker_1)
        self.pushButton_5.clicked.connect(self.stop_worker_2)
        self.pushButton_6.clicked.connect(self.stop_worker_3)
        self.pushButton_7.clicked.connect(self.start_worker_4)
        self.pushButton_8.clicked.connect(self.stop_worker_4)

    #点击按纽1的信号槽:开始线程1
    def start_worker_1(self):
        self.dicThread[1] = calcuteThread(1,None,0.01)
        self.bthreadopen[1]=True
        self.dicThread[1].start()
        self.dicThread[1].signal_ID.connect(self.threadToWindow)      #将线程1中的自定义信号signal_ID绑定槽函数self.dicThreadToWindow
        self.dicThread[1].signal_OK.connect(self.threadOK)            #将线程1中的自定义信号signal_OK绑定槽函数self.dicThreadOK
        self.pushButton_1.setEnabled(False)
        self.pushButton_4.setEnabled(True)
    #点击按纽2的信号槽:开始线程2
    def start_worker_2(self):
        self.dicThread[2] = calcuteThread(2,None,0.01)
        self.bthreadopen[2]=True
        self.dicThread[2].start()
        self.dicThread[2].signal_ID.connect(self.threadToWindow)    #将线程2中的自定义信号signal_ID绑定槽函数self.dicThreadToWindow
        self.pushButton_2.setEnabled(False)
        self.pushButton_5.setEnabled(True)
    #点击按纽3的信号槽:开始线程3,用于计算数据集self.lstDatas中的0-5段数据集,比如对一个几百上千万的大数据集,分解成10块数据,用10个线程分别计算分配的子块数据集,最后将各线程计算的数据集合并计算结果即可,避免在一个主进程中来计算全部数据
    def start_worker_3(self):
        self.startTime3=time.time()  #记录线程3从开始到计算完成用的时间
        self.edita3.setText('开始计算数据集self.lstDatas中的0-4段数据,请等待计算结果。。。。。。')
        lstDatas_3=[self.lstDatas,0,5]       #本线程处理计算lstDatas数据中的0-4号数据,因datas为列表,在多线程中对此self.lstDatas处理后的值已是处理后值了,要避免对同一区域数据不同的地方都在计算处理,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mr_LuoWei2009

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值