写在前面
1、QThread类,使用run方法
2、使用movetothread方法
3、使用线程池
区别
1、使用 moveToThread 方法:
通过将QObject子对象移动到线程中执行,可以实现对象在不同线程中的管理和执行。适合于将现有的对象移动到其他线程中执行,比较灵活。
2、封装 QThread 类并调用 run 方法:
创建一个继承自 QThread 的子类,并重写 run 方法来实现线程执行的逻辑。可以更直接地控制线程的创建和执行过程。可以在 run 方法中实现线程的主要逻辑,使得代码更清晰。
3、线程池
继承 QRunnable 并使用 QThreadPool::globalInstance() 线程池,通过继承 QRunnable 类并在其中实现 run 方法,然后将 QRunnable 对象添加到全局线程池中执行。适用于需要管理多个任务的情况,可以方便地控制任务的执行和线程池的管理。
总的来说,使用 moveToThread 方法更适合于将现有的对象移动到其他线程中执行,而封装 QThread 类并调用 run 方法更适合于直接控制线程的创建和执行过程。选择哪种方式取决于具体的需求和设计。
案例----多种排序算法
一、不使用多线程的情况
随机生成10000个自然数,以此进行冒泡、选择、插入和快速排序
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(this->ui->pushButtonGen, &QPushButton::clicked, this, &MainWindow::GenerateArr);
connect(this->ui->pushButtonSort, &QPushButton::clicked, this, [=](){
QElapsedTimer timer;
timer.start();
BubbleSort(m_arr);
SelectSort(m_arr);
InsertSort(m_arr);
QuickSortFunction(m_arr);
int TotalTime = timer.elapsed();
this->ui->label_total->setText("Total Time: "+QString::number(TotalTime)+" ms");
});
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::GenerateArr()
{
for (int i = 0; i < 10000; ++i) {
int randomNumber = rand() % 10000;
this->m_arr.append(randomNumber);
}
QStringList arrlist;
for (int a : m_arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->listViewOrigin->setModel(model);
}
void MainWindow::BubbleSort(QVector<int> arr)
{
QElapsedTimer timer;
timer.start();
for (int i = 0; i < arr.length(); ++i) {
for (int j = 0; j < arr.length()-i-1; ++j) {
if(arr[j]>arr[j+1]){
std::swap(arr[j],arr[j+1]);
}
}
this->ui->progressBarBubble->setValue((i+1) * 100 / arr.length());
}
int time = timer.elapsed();
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->label_bubble->setText("time: "+QString::number(time)+" ms");
this->ui->listViewBubble->setModel(model);
}
void MainWindow::SelectSort(QVector<int> arr)
{
QElapsedTimer timer;
timer.start();
for (int i = 0; i < arr.length(); ++i) {
int minIndex = i;
for (int j = i; j < arr.length(); ++j) {
if(arr[j]<arr[minIndex]){
minIndex = j;
}
}
std::swap(arr[i],arr[minIndex]);
this->ui->progressBarSelect->setValue((i+1) * 100 / arr.length());
}
int time = timer.elapsed();
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->label_select->setText("time: "+QString::number(time)+" ms");
this->ui->listViewSelect->setModel(model);
}
void MainWindow::InsertSort(QVector<int> arr)
{
QElapsedTimer timer;
timer.start();
for (int i = 1; i < arr.length(); ++i) {
for (int j = i; j > 0; --j) {
if(arr[j-1]>arr[j]){
std::swap(arr[j-1],arr[j]);
}
else{
break;
}
}
this->ui->progressBarInsert->setValue((i+1) * 100 / arr.length());
}
int time = timer.elapsed();
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->label_insert->setText("time :"+QString::number(time)+" ms");
this->ui->listViewInsert->setModel(model);
}
int MainWindow::getMid(QVector<int> &arr, int low, int high)
{
int mid = arr[high]; // 选择中间位置的元素作为中间值
int left = low - 1;
for (int i = low; i < high; ++i) {
if (arr[i] < mid) {
left++;
std::swap(arr[i], arr[left]);
}
}
std::swap(arr[left + 1], arr[high]);
return left + 1;
}
void MainWindow::QuickSort(QVector<int> &arr,int low, int high)
{
if(low<high){
int mid = getMid(arr, low, high);
QuickSort(arr, low, mid-1);
QuickSort(arr, mid+1, high);
// int progress = qRound((mid - low + 1) * 100.0 / (high - low + 1));
// this->ui->progressBarQuick->setValue(progress);
}
}
void MainWindow::QuickSortFunction(QVector<int> arr)
{
QElapsedTimer timer;
timer.start();
QuickSort(arr, 0, arr.length()-1);
int time = timer.elapsed();
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->label_quick->setText("time: "+QString::number(time)+" ms");
this->ui->listViewQuick->setModel(model);
}
运行结果:快排遥遥领先,冒泡遥遥落后,总用时4736
二、QThread类方法
思路是对每个排序算法进行线程类封装,在主线程中启动多个子线程(偷懒了,没写快排)
子线程,以冒排为例:
#ifndef SORTTHREAD_H
#define SORTTHREAD_H
#include <QObject>
#include <QThread>
class SortThread : public QThread
{
Q_OBJECT
public:
explicit SortThread(QObject *parent = nullptr);
void run() override;
void getArr(QVector<int> arr);
signals:
void finishSort(QVector<int> arr, int time);
void sendProgressValue(int value);
private:
QVector<int> m_arr;
};
#endif // SORTTHREAD_H
#include "sortthread.h"
SortThread::SortThread(QObject *parent)
: QThread{parent}
{}
void SortThread::run()
{
QElapsedTimer timer;
timer.start();
for (int i = 0; i < m_arr.length(); ++i) {
for (int j = 0; j < m_arr.length()-i-1; ++j) {
if(m_arr[j]>m_arr[j+1]){
std::swap(m_arr[j],m_arr[j+1]);
}
}
emit sendProgressValue((i+1)*100/m_arr.length());
}
int time = timer.elapsed();
emit finishSort(m_arr,time);
}
void SortThread::getArr(QVector<int> arr)
{
this->m_arr = arr;
}
主线程:
#include "insertthread.h"
#include "mainwindow.h"
#include "sortthread.h"
#include "ui_mainwindow.h"
#include <selectSortThread.h>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
SortThread *Sortthread = new SortThread;
selectSortThread *selectThread = new selectSortThread;
InsertThread *insertThread = new InsertThread;
connect(this->ui->pushButtonGen, &QPushButton::clicked, this, &MainWindow::GenerateArr);
connect(this->ui->pushButtonSort, &QPushButton::clicked, this, [=](){
Sortthread->getArr(m_arr);
selectThread->getArr(m_arr);
insertThread->getArr(m_arr);
Sortthread->start();
selectThread->start();
insertThread->start();
});
connect(this->ui->pushButtonSort, &QPushButton::clicked, this, [=](){
this->beginTiming();
});
connect(Sortthread, &SortThread::finishSort, this,[=](QVector<int> arr, int time){
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->listViewBubble->setModel(model);
this->ui->label_bubble->setText("time: "+QString::number(time)+" ms");
this->finishedIndex++;
if(finishedIndex==3){
this->ui->label_total->setText("time: "+QString::number(m_totalTimer.elapsed())+" ms");
}
});
connect(Sortthread, &SortThread::sendProgressValue, this, [=](int value){
this->ui->progressBarBubble->setValue(value);
});
connect(selectThread, &selectSortThread::finishSort, this, [=](QVector<int> arr, int time){
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->listViewSelect->setModel(model);
this->ui->label_select->setText("time: "+QString::number(time)+" ms");
this->finishedIndex++;
if(finishedIndex==3){
this->ui->label_total->setText("time: "+QString::number(m_totalTimer.elapsed())+" ms");
}
});
connect(selectThread, &selectSortThread::sendProgressValue, this, [=](int value){
this->ui->progressBarSelect->setValue(value);
});
connect(insertThread, &InsertThread::finishSort, this, [=](QVector<int> arr, int time){
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->listViewInsert->setModel(model);
this->ui->label_insert->setText("time: "+QString::number(time)+" ms");
this->finishedIndex++;
if(finishedIndex==3){
this->ui->label_total->setText("time: "+QString::number(m_totalTimer.elapsed())+" ms");
}
});
connect(insertThread, &InsertThread::sendProgressValue, this, [=](int value){
this->ui->progressBarInsert->setValue(value);
});
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::beginTiming()
{
this->m_totalTimer.start();
}
结果:总用时节省一半
三、moveToThread()方法
三个任务类:
class BubbleWorker: public QObject
{
Q_OBJECT
public:
void sort();
void getArr(QVector<int> arr);
signals:
void finishSort(QVector<int> arr);
private:
QVector<int> m_arr;
};
class SelectWorker: public QObject
{
Q_OBJECT
public:
void sort();
void getArr(QVector<int> arr);
signals:
void finishSort(QVector<int> arr);
private:
QVector<int> m_arr;
};
class InsertWorker: public QObject
{
Q_OBJECT
public:
void sort();
void getArr(QVector<int> arr);
signals:
void finishSort(QVector<int> arr);
private:
QVector<int> m_arr;
};
void BubbleWorker::sort()
{
for (int i = 0; i < m_arr.length(); ++i) {
for (int j = 0; j < m_arr.length()-i-1; ++j) {
if(m_arr[j]>m_arr[j+1]){
std::swap(m_arr[j],m_arr[j+1]);
}
}
}
emit finishSort(m_arr);
}
void BubbleWorker::getArr(QVector<int> arr)
{
m_arr= arr;
}
void SelectWorker::sort()
{
for (int i = 0; i < m_arr.length(); ++i) {
int minIndex = i;
for (int j = i; j < m_arr.length(); ++j) {
if(m_arr[j]<m_arr[minIndex]){
minIndex = j;
}
}
std::swap(m_arr[i],m_arr[minIndex]);
}
emit finishSort(m_arr);
}
void SelectWorker::getArr(QVector<int> arr)
{
m_arr= arr;
}
void InsertWorker::sort()
{
for (int i = 1; i < m_arr.length(); ++i) {
for (int j = i; j > 0; --j) {
if(m_arr[j-1]>m_arr[j]){
std::swap(m_arr[j-1],m_arr[j]);
}
else{
break;
}
}
}
emit finishSort(m_arr);
}
void InsertWorker::getArr(QVector<int> arr)
{
m_arr= arr;
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButtonGen, &QPushButton::clicked, this , &MainWindow::GenerateArr);
BubbleWorker *bworker = new BubbleWorker;
SelectWorker *sworker = new SelectWorker;
InsertWorker *iworker = new InsertWorker;
QThread *t1 = new QThread;
QThread *t2 = new QThread;
QThread *t3 = new QThread;
bworker->moveToThread(t1);
sworker->moveToThread(t2);
iworker->moveToThread(t3);
connect(ui->pushButtonSort, &QPushButton::clicked, this, [=](){
t1->start();
t2->start();
t3->start();
});
connect(t1, &QThread::started, this, [=](){
bworker->getArr(m_arr);
bworker->sort();
});
connect(t2, &QThread::started, this, [=](){
sworker->getArr(m_arr);
sworker->sort();
});
connect(t3, &QThread::started, this, [=](){
iworker->getArr(m_arr);
iworker->sort();
});
connect(bworker, &BubbleWorker::finishSort, this, [=](QVector<int> arr){
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->listViewBubble->setModel(model);
});
connect(sworker, &SelectWorker::finishSort, this, [=](QVector<int> arr){
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->listViewSelect->setModel(model);
});
connect(iworker, &InsertWorker::finishSort, this, [=](QVector<int> arr){
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->listViewInsert->setModel(model);
});
connect(this, &MainWindow::destroyed, this, [=](){
t1->quit();
t2->quit();
t3->quit();
bworker->deleteLater();
sworker->deleteLater();
iworker->deleteLater();
});
}
四、线程池方法
子线程类继承于QRunnable类,重写run方法
class BubbleWorker: public QObject, public QRunnable
{
Q_OBJECT
public:
void run() override;
void getArr(QVector<int> arr);
signals:
void finishSort(QVector<int> arr);
private:
QVector<int> m_arr;
};
class SelectWorker: public QObject, public QRunnable
{
Q_OBJECT
public:
void run() override;
void getArr(QVector<int> arr);
signals:
void finishSort(QVector<int> arr);
private:
QVector<int> m_arr;
};
class InsertWorker: public QObject, public QRunnable
{
Q_OBJECT
public:
void run() override;
void getArr(QVector<int> arr);
signals:
void finishSort(QVector<int> arr);
private:
QVector<int> m_arr;
};
void BubbleWorker::run()
{
for (int i = 0; i < m_arr.length(); ++i) {
for (int j = 0; j < m_arr.length()-i-1; ++j) {
if(m_arr[j]>m_arr[j+1]){
std::swap(m_arr[j],m_arr[j+1]);
}
}
}
emit finishSort(m_arr);
}
void BubbleWorker::getArr(QVector<int> arr)
{
m_arr= arr;
}
void SelectWorker::run()
{
for (int i = 0; i < m_arr.length(); ++i) {
int minIndex = i;
for (int j = i; j < m_arr.length(); ++j) {
if(m_arr[j]<m_arr[minIndex]){
minIndex = j;
}
}
std::swap(m_arr[i],m_arr[minIndex]);
}
emit finishSort(m_arr);
}
void SelectWorker::getArr(QVector<int> arr)
{
m_arr= arr;
}
void InsertWorker::run()
{
for (int i = 1; i < m_arr.length(); ++i) {
for (int j = i; j > 0; --j) {
if(m_arr[j-1]>m_arr[j]){
std::swap(m_arr[j-1],m_arr[j]);
}
else{
break;
}
}
}
emit finishSort(m_arr);
}
void InsertWorker::getArr(QVector<int> arr)
{
m_arr= arr;
}
主线程中声明三个子线程,通过globalInstance方法添加到线程池中.
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
BubbleWorker *bworker = new BubbleWorker;
SelectWorker *sworker = new SelectWorker;
InsertWorker *iworker = new InsertWorker;
connect(ui->pushButtonGen, &QPushButton::clicked, this , &MainWindow::GenerateArr);
connect(ui->pushButtonSort, &QPushButton::clicked, this, [=](){
bworker->getArr(m_arr);
sworker->getArr(m_arr);
iworker->getArr(m_arr);
QThreadPool::globalInstance()->start(bworker);
QThreadPool::globalInstance()->start(sworker);
QThreadPool::globalInstance()->start(iworker);
});
connect(bworker, &BubbleWorker::finishSort, this,[=](QVector<int> arr){
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->listViewBubble->setModel(model);
});
connect(sworker, &SelectWorker::finishSort, this,[=](QVector<int> arr){
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->listViewSelect->setModel(model);
});
connect(iworker, &InsertWorker::finishSort, this,[=](QVector<int> arr){
QStringList arrlist;
for (int a : arr) {
arrlist.append(QString::number(a));
}
QStringListModel *model = new QStringListModel(arrlist);
this->ui->listViewInsert->setModel(model);
});
//释放内存
connect(this, &MainWindow::destroyed, this, [=](){
bworker->deleteLater();
sworker->deleteLater();
iworker->deleteLater();
});
}
效果:(个人感觉最流畅)