網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
一、目的
??現(xiàn)在所有的高性能服務(wù)器程序,幾乎都會(huì)使用到線(xiàn)程池技術(shù),從而更好且有效的榨干服務(wù)器性能。而創(chuàng)建并銷(xiāo)毀線(xiàn)程的過(guò)程勢(shì)必會(huì)消耗內(nèi)存。而在日常開(kāi)發(fā)中內(nèi)存資源是及其寶貴的,所以QT 多線(xiàn)程之線(xiàn)程池QThreadPool就有很大用處了。它可以用來(lái)管理線(xiàn)程的優(yōu)先順序,防止創(chuàng)建過(guò)多的線(xiàn)程,起到很好的管理作用。
二、最優(yōu)線(xiàn)程數(shù)
??線(xiàn)程的創(chuàng)建和銷(xiāo)毀是有性能開(kāi)銷(xiāo)的,當(dāng)我們有少量業(yè)務(wù)需要處理時(shí),我們可以放到線(xiàn)程中完成,甚至可以多開(kāi)幾個(gè)線(xiàn)程并行處理。
那么,問(wèn)題來(lái)了,如果需要海量的數(shù)據(jù)處理,難道無(wú)休止的開(kāi)線(xiàn)程下去嗎?
首先,要明白CPU的性能是有限的,每個(gè)線(xiàn)程好比一個(gè)處理時(shí)間片,多個(gè)線(xiàn)程之間切換處理,CPU線(xiàn)程上下文來(lái)回切換,這個(gè)也是需要消耗時(shí)間的。所以,物極必反,當(dāng)線(xiàn)程數(shù)量到達(dá)一個(gè)點(diǎn)后,可能消耗在線(xiàn)程切換的時(shí)間,會(huì)大于實(shí)際線(xiàn)程處理業(yè)務(wù)的時(shí)間,這個(gè)可以想象的到。
那么很容易明白:線(xiàn)程數(shù)并不是越多越好,而是某個(gè)范圍或者某個(gè)經(jīng)驗(yàn)值。
一般來(lái)講,我們可以認(rèn)為,最佳性能線(xiàn)程數(shù)==CPU邏輯核心數(shù)量,比如CPU是4核8線(xiàn)程,那么開(kāi)8個(gè)線(xiàn)程可以達(dá)到性能最佳。
一般電腦是開(kāi)啟超線(xiàn)程的,也就是4核可以模擬出8個(gè)邏輯核,故稱(chēng)4核8線(xiàn)程。
QThreadPool線(xiàn)程池默認(rèn)最大線(xiàn)程數(shù),也是CPU邏輯Core的數(shù)量。
嚴(yán)格意義來(lái)講,最佳線(xiàn)程數(shù)還與處理業(yè)務(wù)類(lèi)型有關(guān),如業(yè)務(wù)屬于IO密集型、CPU密集型,根據(jù)經(jīng)驗(yàn)推斷:
- IO密集型,頻繁讀取磁盤(pán)上的數(shù)據(jù),或者需要通過(guò)網(wǎng)絡(luò)遠(yuǎn)程調(diào)用接口。線(xiàn)程數(shù)經(jīng)驗(yàn)值是:2N,其中N代表CPU邏輯Core數(shù);
- CPU密集型,非常復(fù)雜的調(diào)用,循環(huán)次數(shù)很多,或者遞歸調(diào)用層次很深等。線(xiàn)程數(shù)經(jīng)驗(yàn)值是:N + 1,其中N代表CPU邏輯Core數(shù)。
三、線(xiàn)程池的原理
最佳性能線(xiàn)程數(shù)可以認(rèn)為等于CPU邏輯核心數(shù)量N,所以我們?cè)O(shè)計(jì)程序,為了得到更好的性能,需要實(shí)現(xiàn)如下的需求:
- 限制創(chuàng)建最大線(xiàn)程數(shù)量<=N;
- 盡可能復(fù)用線(xiàn)程,避免頻繁創(chuàng)建和銷(xiāo)毀線(xiàn)程資源,降低無(wú)謂消耗;
- 線(xiàn)程在空閑時(shí),應(yīng)該休息,避免占用CPU資源;
- 線(xiàn)程在有業(yè)務(wù)需要處理時(shí),需要激活;
- 當(dāng)業(yè)務(wù)來(lái)了,這N個(gè)線(xiàn)程如何分配;
上述問(wèn)題,高度封裝的QThreadPool線(xiàn)程池可以解決。
線(xiàn)程池的優(yōu)點(diǎn):
- 創(chuàng)建和銷(xiāo)毀線(xiàn)程需要和OS交互,少量線(xiàn)程影響不大,但是線(xiàn)程數(shù)量太大,勢(shì)必會(huì)影響性能,使用線(xiàn)程池可以這種開(kāi)銷(xiāo);
- 線(xiàn)程池維護(hù)一定數(shù)量的線(xiàn)程,使用時(shí),將指定函數(shù)傳遞給線(xiàn)程池,線(xiàn)程池會(huì)在線(xiàn)程中執(zhí)行任務(wù);
- 線(xiàn)程池,屬于對(duì)象池,對(duì)象池都是為了復(fù)用,以避免頻繁申請(qǐng)和釋放對(duì)象所造成的性能損失。
- 線(xiàn)程池創(chuàng)建好后,池內(nèi)默認(rèn)一個(gè)線(xiàn)程也沒(méi)有,當(dāng)通過(guò)相關(guān)函數(shù)加入任務(wù)后,線(xiàn)程池根據(jù)任務(wù)數(shù)量會(huì)自動(dòng)創(chuàng)建線(xiàn)程,任務(wù)會(huì)合理分配到各個(gè)線(xiàn)程上執(zhí)行,但是線(xiàn)程總數(shù)量不會(huì)超過(guò)設(shè)定的最大值。
- 若任務(wù)處理完畢,則池內(nèi)所有線(xiàn)程進(jìn)入掛起狀態(tài),不占用CPU時(shí)間片,待任務(wù)再次到來(lái),便會(huì)激活部分或全部線(xiàn)程,處理任務(wù)。
- 若任務(wù)過(guò)多,當(dāng)前沒(méi)有空閑的線(xiàn)程,則新增任務(wù)會(huì)被放置到緩存隊(duì)列中,等待線(xiàn)程空閑后,再進(jìn)行處理,這樣,每個(gè)任務(wù)與線(xiàn)程可以有一個(gè)合理的分配,相當(dāng)于實(shí)現(xiàn)了業(yè)務(wù)處理的負(fù)載均衡。故而可以以最好的性能來(lái)處理業(yè)務(wù)。
四、QThreadPool線(xiàn)程池
下面是QThreadPool的常用函數(shù):
int activeThreadCount() const //當(dāng)前的活動(dòng)線(xiàn)程數(shù)量
void clear()//清除所有當(dāng)前排隊(duì)但未開(kāi)始運(yùn)行的任務(wù)
int expiryTimeout() const//線(xiàn)程長(zhǎng)時(shí)間未使用將會(huì)自動(dòng)退出節(jié)約資源,此函數(shù)返回等待時(shí)間
int maxThreadCount() const//線(xiàn)程池可維護(hù)的最大線(xiàn)程數(shù)量
void releaseThread()//釋放被保留的線(xiàn)程
void reserveThread()//保留線(xiàn)程,此線(xiàn)程將不會(huì)占用最大線(xiàn)程數(shù)量,從而可能會(huì)引起當(dāng)前活動(dòng)線(xiàn)程數(shù)量大于最大線(xiàn)程數(shù)量的情況
void setExpiryTimeout(int expiryTimeout)//設(shè)置線(xiàn)程回收的等待時(shí)間
void setMaxThreadCount(int maxThreadCount)//設(shè)置最大線(xiàn)程數(shù)量
void setStackSize(uint stackSize)//此屬性包含線(xiàn)程池工作線(xiàn)程的堆棧大小。
uint stackSize() const//堆大小
void start(QRunnable *runnable, int priority = 0)//加入一個(gè)運(yùn)算到隊(duì)列,注意start不一定立刻啟動(dòng),只是插入到隊(duì)列,排到了才會(huì)開(kāi)始運(yùn)行。需要傳入QRunnable ,后續(xù)介紹
bool tryStart(QRunnable *runnable)//嘗試啟動(dòng)一個(gè)
bool tryTake(QRunnable *runnable)//刪除隊(duì)列中的一個(gè)QRunnable,若當(dāng)前QRunnable 未啟動(dòng)則返回成功,正在運(yùn)行則返回失敗
bool waitForDone(int?<i>msecs</i>?=?-1)//等待所有線(xiàn)程運(yùn)行結(jié)束并退出,參數(shù)為等待時(shí)間-1表示一直等待到最后一個(gè)線(xiàn)程退出
QRunnable類(lèi):所有runable對(duì)象的基類(lèi)。
QRunnable類(lèi)是一個(gè)接口, 用于表示需要執(zhí)行的任務(wù)或代碼段, 具體任務(wù)在run() 函數(shù)內(nèi)部實(shí)現(xiàn)??梢允褂肣ThreadPool在各個(gè)獨(dú)立的線(xiàn)程中執(zhí)行代碼。如果autoDelete() 返回true (默認(rèn)值), QThreadPool將自動(dòng)刪除QRunnable 。使用setAutoDelete() 可更改是否自動(dòng)刪除。
QThreadPool 是創(chuàng)建線(xiàn)程池函數(shù),QRunnable是線(xiàn)程池的線(xiàn)程具體執(zhí)行操作函數(shù),兩者要搭配使用。
五、QThreadPool簡(jiǎn)單示例
執(zhí)行效果如下:
#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();
}
注意:
線(xiàn)程池使用時(shí)傳入繼承于的QRunnable類(lèi)對(duì)象(并啟動(dòng)該線(xiàn)程對(duì)象),并且線(xiàn)程池會(huì)自主釋放在其中的線(xiàn)程(提高程序性能),還能實(shí)現(xiàn)并發(fā),提高效率;不過(guò)不能使用信號(hào)槽進(jìn)行通信,需要使用QMetaObject::invokeMethod進(jìn)行通信。
原文鏈接:https://blog.csdn.net/m0_37251750/article/details/126428229
相關(guān)推薦
- 2023-02-12 redis加鎖的三種方式小結(jié)_Redis
- 2022-07-01 淺談C語(yǔ)言中的sizeof()和strlen()的區(qū)別_C 語(yǔ)言
- 2022-08-16 Containerd容器運(yùn)行yum安裝與二進(jìn)制安裝_云其它
- 2022-12-10 Android入門(mén)之計(jì)時(shí)器Chronometer的使用教程_Android
- 2023-10-09 所有的引用類(lèi)型都有自由可拓展性怎么理解
- 2022-04-25 Entity?Framework?Core中執(zhí)行SQL語(yǔ)句和存儲(chǔ)過(guò)程的方法介紹_實(shí)用技巧
- 2022-07-29 C語(yǔ)言深入回顧講解結(jié)構(gòu)體對(duì)齊_C 語(yǔ)言
- 2022-04-23 git如何提交本地倉(cāng)庫(kù)并同步碼云倉(cāng)庫(kù)
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支