網站首頁 編程語言 正文
一、目的
??現在所有的高性能服務器程序,幾乎都會使用到線程池技術,從而更好且有效的榨干服務器性能。而創建并銷毀線程的過程勢必會消耗內存。而在日常開發中內存資源是及其寶貴的,所以QT 多線程之線程池QThreadPool就有很大用處了。它可以用來管理線程的優先順序,防止創建過多的線程,起到很好的管理作用。
二、最優線程數
??線程的創建和銷毀是有性能開銷的,當我們有少量業務需要處理時,我們可以放到線程中完成,甚至可以多開幾個線程并行處理。
那么,問題來了,如果需要海量的數據處理,難道無休止的開線程下去嗎?
首先,要明白CPU的性能是有限的,每個線程好比一個處理時間片,多個線程之間切換處理,CPU線程上下文來回切換,這個也是需要消耗時間的。所以,物極必反,當線程數量到達一個點后,可能消耗在線程切換的時間,會大于實際線程處理業務的時間,這個可以想象的到。
那么很容易明白:線程數并不是越多越好,而是某個范圍或者某個經驗值。
一般來講,我們可以認為,最佳性能線程數==CPU邏輯核心數量,比如CPU是4核8線程,那么開8個線程可以達到性能最佳。
一般電腦是開啟超線程的,也就是4核可以模擬出8個邏輯核,故稱4核8線程。
QThreadPool線程池默認最大線程數,也是CPU邏輯Core的數量。
嚴格意義來講,最佳線程數還與處理業務類型有關,如業務屬于IO密集型、CPU密集型,根據經驗推斷:
- IO密集型,頻繁讀取磁盤上的數據,或者需要通過網絡遠程調用接口。線程數經驗值是:2N,其中N代表CPU邏輯Core數;
- CPU密集型,非常復雜的調用,循環次數很多,或者遞歸調用層次很深等。線程數經驗值是:N + 1,其中N代表CPU邏輯Core數。
三、線程池的原理
最佳性能線程數可以認為等于CPU邏輯核心數量N,所以我們設計程序,為了得到更好的性能,需要實現如下的需求:
- 限制創建最大線程數量<=N;
- 盡可能復用線程,避免頻繁創建和銷毀線程資源,降低無謂消耗;
- 線程在空閑時,應該休息,避免占用CPU資源;
- 線程在有業務需要處理時,需要激活;
- 當業務來了,這N個線程如何分配;
上述問題,高度封裝的QThreadPool線程池可以解決。
線程池的優點:
- 創建和銷毀線程需要和OS交互,少量線程影響不大,但是線程數量太大,勢必會影響性能,使用線程池可以這種開銷;
- 線程池維護一定數量的線程,使用時,將指定函數傳遞給線程池,線程池會在線程中執行任務;
- 線程池,屬于對象池,對象池都是為了復用,以避免頻繁申請和釋放對象所造成的性能損失。
- 線程池創建好后,池內默認一個線程也沒有,當通過相關函數加入任務后,線程池根據任務數量會自動創建線程,任務會合理分配到各個線程上執行,但是線程總數量不會超過設定的最大值。
- 若任務處理完畢,則池內所有線程進入掛起狀態,不占用CPU時間片,待任務再次到來,便會激活部分或全部線程,處理任務。
- 若任務過多,當前沒有空閑的線程,則新增任務會被放置到緩存隊列中,等待線程空閑后,再進行處理,這樣,每個任務與線程可以有一個合理的分配,相當于實現了業務處理的負載均衡。故而可以以最好的性能來處理業務。
四、QThreadPool線程池
下面是QThreadPool的常用函數:
int activeThreadCount() const //當前的活動線程數量
void clear()//清除所有當前排隊但未開始運行的任務
int expiryTimeout() const//線程長時間未使用將會自動退出節約資源,此函數返回等待時間
int maxThreadCount() const//線程池可維護的最大線程數量
void releaseThread()//釋放被保留的線程
void reserveThread()//保留線程,此線程將不會占用最大線程數量,從而可能會引起當前活動線程數量大于最大線程數量的情況
void setExpiryTimeout(int expiryTimeout)//設置線程回收的等待時間
void setMaxThreadCount(int maxThreadCount)//設置最大線程數量
void setStackSize(uint stackSize)//此屬性包含線程池工作線程的堆棧大小。
uint stackSize() const//堆大小
void start(QRunnable *runnable, int priority = 0)//加入一個運算到隊列,注意start不一定立刻啟動,只是插入到隊列,排到了才會開始運行。需要傳入QRunnable ,后續介紹
bool tryStart(QRunnable *runnable)//嘗試啟動一個
bool tryTake(QRunnable *runnable)//刪除隊列中的一個QRunnable,若當前QRunnable 未啟動則返回成功,正在運行則返回失敗
bool waitForDone(int?<i>msecs</i>?=?-1)//等待所有線程運行結束并退出,參數為等待時間-1表示一直等待到最后一個線程退出
QRunnable類:所有runable對象的基類。
QRunnable類是一個接口, 用于表示需要執行的任務或代碼段, 具體任務在run() 函數內部實現。可以使用QThreadPool在各個獨立的線程中執行代碼。如果autoDelete() 返回true (默認值), QThreadPool將自動刪除QRunnable 。使用setAutoDelete() 可更改是否自動刪除。
QThreadPool 是創建線程池函數,QRunnable是線程池的線程具體執行操作函數,兩者要搭配使用。
五、QThreadPool簡單示例
執行效果如下:
#include <QCoreApplication>
#include <QThreadPool>
#include <QDebug>
class Task1 : public QRunnable
{
public:
Task1()
{ }
virtual ~Task1() override
{
qDebug() << "~Task1()";
}
virtual void run() override
{
qDebug() << "do Task1 work:" << QThread::currentThreadId();
}
};
class Task2 : public QRunnable
{
public:
Task2()
{ }
virtual ~Task2() override
{
qDebug() << "~Task2()";
}
virtual void run() override
{
qDebug() << "do Task2 work:" << QThread::currentThreadId();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Task1* task1 = new Task1();
Task2* task2 = new Task2();
QThreadPool threadPool;
threadPool.start(task1);
threadPool.start(task2);
threadPool.waitForDone();
return a.exec();
}
注意:
線程池使用時傳入繼承于的QRunnable類對象(并啟動該線程對象),并且線程池會自主釋放在其中的線程(提高程序性能),還能實現并發,提高效率;不過不能使用信號槽進行通信,需要使用QMetaObject::invokeMethod進行通信。
原文鏈接:https://blog.csdn.net/m0_37251750/article/details/126428229
相關推薦
- 2022-05-03 SQL?Server查詢某個字段在哪些表中存在_MsSql
- 2022-07-21 windows與Linux查看端口占用并終止端口占用
- 2022-01-02 前端生成二維碼及把頁面轉為圖片保存到本地
- 2022-10-20 Flutter投票組件使用方法詳解_Android
- 2022-08-19 redis在windows下啟動# Creating Server TCP listening so
- 2022-08-18 Android顏色處理SweepGradient掃描及梯度渲染示例_Android
- 2022-06-04 Jenkins初級應用Publish?Over?SSH插件配置_安裝教程
- 2023-03-26 TypeScript?基本數據類型實例詳解_其它
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支