王 鑫,扈 月,劉坤禹,王歡歡,甄帥輝
(1 中國電子科技集團公司第三十研究所 四川 成都 610041)
(2 中國人民解放軍31012 部隊 北京 100091)
線程是操作系統(tǒng)能夠進行運算調(diào)度的最小單位,它被包含在進程之中,是進程中的實際運作單位[1]。多線程技術(shù)主要解決任務(wù)并發(fā)的問題,它的核心在于將宏觀的任務(wù)量拆解為微觀的任務(wù)分量,將任務(wù)分量派發(fā)到不同的線程上,從而減少任務(wù)的處理時間。多線程使用場景一般分為兩種:第一種為按需分配,即針對每個任務(wù)派生一個獨立的線程去處理該任務(wù),雖然在任務(wù)量少的應(yīng)用中,該方式處理效率高,但是在任務(wù)量巨大的應(yīng)用中,該方式在線程創(chuàng)建和銷毀中將耗費大量時間;第二種為預(yù)先分配,即提前創(chuàng)建包含一定數(shù)目線程的線程池,線程池又分為靜態(tài)線程池和動態(tài)線程池兩種,靜態(tài)線程池通過預(yù)先創(chuàng)建包含固定數(shù)量線程的線程池去處理任務(wù),動態(tài)線程池相較于靜態(tài)線程池的不同點在于可以通過任務(wù)量的變化動態(tài)調(diào)整線程池中線程的數(shù)量,它們都能節(jié)省線程的創(chuàng)建和銷毀時間,從而降低每個線程的平均創(chuàng)建和銷毀時間。
靜態(tài)線程池預(yù)先創(chuàng)建一定數(shù)量線程后,線程數(shù)量不再變化,用以處理所有任務(wù),但當任務(wù)達到波峰時,任務(wù)響應(yīng)時間將會加大,降低用戶體驗感。動態(tài)線程池也是預(yù)先創(chuàng)建一定數(shù)量線程后,通過對任務(wù)量的分析,動態(tài)調(diào)整線程池中線程數(shù)量的大小,降低任務(wù)響應(yīng)時間。動態(tài)線程池實現(xiàn)時面臨一些問題,例如動態(tài)調(diào)整線程池系數(shù)不恰當和單個工作線程如何回收銷毀。
本文將對以上提出的三種多任務(wù)處理模型進行分析,并著重優(yōu)化設(shè)計動態(tài)線程池,通過不同規(guī)模的模擬任務(wù),不同模型參數(shù)的調(diào)整,對比驗證三種模型。
多線程方案即“隨時請求,隨時創(chuàng)建,隨時回收”,任務(wù)請求送入任務(wù)調(diào)度模塊,任務(wù)調(diào)度模塊創(chuàng)建線程進行任務(wù)請求處理,任務(wù)處理完畢后,線程回收模塊進行線程的回收和銷毀,面對多少任務(wù),即需創(chuàng)建多少個線程進行任務(wù)處理。
該方案邏輯簡單,實現(xiàn)便捷,適用于小規(guī)模且無周期性的任務(wù)量。但是當任務(wù)量爆發(fā)式增長時,該方案受限于操作系統(tǒng)和硬件資源所能創(chuàng)建的線程數(shù)總量,當線程數(shù)達到上限后,新來的任務(wù)將不能得到及時處理[2]。
靜態(tài)線程池方案即“預(yù)先創(chuàng)建,隨時請求,統(tǒng)一回收”,初始化模塊創(chuàng)建預(yù)先設(shè)定數(shù)量M 的線程,當出現(xiàn)任務(wù)請求,通過任務(wù)入隊模塊將任務(wù)存入任務(wù)隊列中,線程池從任務(wù)隊列中獲取任務(wù),進行任務(wù)處理,線程池的數(shù)量始終保持不變。方案示意如圖1 所示。
圖1 靜態(tài)線程池方案示意圖
針對一定規(guī)模且周期性的任務(wù)量,利用靜態(tài)線程池的方案,可以節(jié)省線程創(chuàng)建和銷毀的時間,加快任務(wù)處理速度,提升用戶體驗感。當任務(wù)量達到線程池的數(shù)量M 后,沒有新的線程可以處理任務(wù)隊列中的任務(wù),會加大一些任務(wù)的處理時間,降低用戶體驗感。
動態(tài)線程池方案即“動態(tài)創(chuàng)建,隨時請求,動態(tài)回收”。初始化模塊創(chuàng)建預(yù)先設(shè)定數(shù)量的線程,當出現(xiàn)任務(wù)請求,通過任務(wù)入隊模塊將任務(wù)存入任務(wù)隊列中,線程池從任務(wù)隊列中獲取任務(wù),進行任務(wù)處理。當任務(wù)監(jiān)控模塊檢測到線程池空閑線程數(shù)量在設(shè)定的時間T1 內(nèi)一直為0且任務(wù)隊列中的任務(wù)數(shù)量不為0,任務(wù)監(jiān)控模塊將根據(jù)調(diào)整系數(shù)P1 進行新線程的創(chuàng)建;當任務(wù)監(jiān)控模塊檢測到線程池空閑線程數(shù)量在設(shè)定時間T2 內(nèi)一直不為0 且任務(wù)隊列中的任務(wù)數(shù)據(jù)為0,任務(wù)監(jiān)控模塊將根據(jù)調(diào)整系數(shù)P2進行空閑線程的回收。方案示意如圖2 所示。
圖2 動態(tài)線程池方案示意圖
針對一定規(guī)模、周期性、具有井噴式特性的任務(wù)量,利用動態(tài)線程池的方案,不僅可以節(jié)省線程創(chuàng)建和銷毀的時間,而且當任務(wù)量井噴式地增長時,可以動態(tài)調(diào)整線程數(shù)量,加快任務(wù)處理速度,提升用戶體驗感。當任務(wù)量經(jīng)過潮汐趨于平穩(wěn)時,通過銷毀線程池中空閑的線程,確保線程池的活性[3]。該方案的難點主要為如何確定線程池動態(tài)調(diào)整的系數(shù),如何高效回收空閑線程。
因多線程方案和靜態(tài)線程池方案邏輯和結(jié)構(gòu)簡單,因此下面主要針對動態(tài)線程池進行分析與設(shè)計。
傳統(tǒng)動態(tài)線程池采用“動態(tài)創(chuàng)建,隨時請求,動態(tài)回收”的方式對線程池進行控制,其中動態(tài)調(diào)整線程池線程數(shù)和線程池的空閑線程安全退出機制的選擇對動態(tài)線程池的性能起著關(guān)鍵作用。本文主要針對以上兩點進行分析與設(shè)計。
針對動態(tài)調(diào)整線程數(shù),傳統(tǒng)的做法為基于預(yù)測公式進行線程數(shù)調(diào)整,該方法實現(xiàn)復(fù)雜,且使用場景具有局限性[4]。
固定線程數(shù)量的線程池在某些場景下不能滿足應(yīng)用需求,線程池常見的動態(tài)調(diào)整線程數(shù)量的方案有基于設(shè)定值觸發(fā)和基于任務(wù)量趨勢預(yù)測兩種形式:①基于任務(wù)量趨勢預(yù)測的方式對任務(wù)建模要求高,需要結(jié)合統(tǒng)計學(xué)原理進行任務(wù)量趨勢預(yù)測,能夠真實反映任務(wù)量的變化從而進行高效處理,但是該方式的使用場景具有局限性,且需要較大的算力資源;②基于設(shè)定值觸發(fā)的方式通過預(yù)先設(shè)置不同規(guī)模的參數(shù)集合,通過任務(wù)量的跟蹤選擇合適的參數(shù),實現(xiàn)簡單,線程池維護開銷小且通用性較高。本文為保證線程池的通用性,采用基于設(shè)定值觸發(fā)方式來動態(tài)調(diào)整線程池。
(1)合理設(shè)置相關(guān)參數(shù)
若設(shè)線程池中最大線程數(shù)為T_MAX,最小線程數(shù)為_MIN,最大空閑線程數(shù)為T_FMAX,最小空閑線程數(shù)為T_FMIN,處理原則是:①在線程池初始化階段,創(chuàng)建T_MIN個空閑線程。②線程池中空閑線程數(shù)量T_FNOW 低于T_FMIN 時,通過待處理任務(wù)量派生調(diào)整系數(shù)P1 觸發(fā)線程池調(diào)整進行P1×T_MIN 個線程添加。③線程池中空閑線程數(shù)量T_FNOW 不低于T_FMIN 且小于T_FMAX 時,通過固定調(diào)整系數(shù)P2 觸發(fā)線程池調(diào)整進行P2×(T_FNOWTFMIN)個線程刪除。④線程池中空閑線程數(shù)量不低于T_FMAX 時,通過固定調(diào)整系數(shù)P3 觸發(fā)線程池調(diào)整進行P2×(T_FNOW-TFMAX)個線程刪除。⑤調(diào)整過程中保證調(diào)整后的線程池線程數(shù)量小于T_MAX 且大于等于T_MIN。
(2)延遲銷毀線程
在任務(wù)量激增的情況下通過設(shè)定值觸發(fā)增加一定數(shù)量的線程后,當任務(wù)量減少時,需要銷毀這部分創(chuàng)建的線程。此時并不真正地銷毀這些線程,而是將它放入銷毀列表中,創(chuàng)建并使能定時器。當定時器計時完畢時,若無創(chuàng)建新線程的需求將會銷毀這些線程;如果在定時器計時完畢前,有創(chuàng)建新線程的需求,將刪除該銷毀列表的定時器,并使用這些還未銷毀的線程,根據(jù)任務(wù)量變化重復(fù)前面的步驟,從而達到了提高線程的復(fù)用。
針對空閑線程安全退出,傳統(tǒng)的做法為在線程創(chuàng)建初期進行統(tǒng)計,并對創(chuàng)建的線程進行狀態(tài)監(jiān)控,當需要減少線程數(shù)量時,通過狀態(tài)監(jiān)控發(fā)現(xiàn)空閑線程并進行回收,該方法存在的問題為對線程進行狀態(tài)監(jiān)控將耗費大量計算資源[5]。
線程退出的方式主要分為線程主動退出和線程被動退出兩種,多線程方案和靜態(tài)線程池方案不需要考慮線程退出的方式,直接進行線程回收即可。動態(tài)線程池方案需要考慮線程回收的方式,需檢測線程池中的線程是否處于空閑狀態(tài)。一般采用輪詢或者信號觸發(fā),輪詢即重復(fù)地查詢某個線程的狀態(tài),將會耗費大量的計算資源;信號量方式需要維護大量的信號量,耗費大量的存儲資源。
因此本文提出一種空閑自動釋放機制,當任務(wù)監(jiān)控模塊做出決策應(yīng)減少線程數(shù)量時,將“自殺”任務(wù)放入任務(wù)隊列中,此時空閑線程便無差別地從任務(wù)隊列中領(lǐng)取任務(wù),從而釋放資源,結(jié)束線程。
多線程方案即一任務(wù)一線程,用完即毀,使用操作系統(tǒng)自帶函數(shù)即可實現(xiàn)。
本文通過添加函數(shù)等實現(xiàn)了線程池創(chuàng)建、初始化、獲取線程數(shù)量和獲取線程池狀態(tài)等接口,通過對該系列接口的動態(tài)組合,可以實現(xiàn)靜態(tài)線程池和動態(tài)線程池兩種方案。
(1)使用方法
(2)接口與功能
采用面向?qū)ο蟮乃枷耄瑢⒕€程池的方法定義在sl_thread_pool 結(jié)構(gòu)體中,實現(xiàn)線程池的初始化、狀態(tài)查詢和線程數(shù)量調(diào)整等功能。
針對多線程方案,通過任務(wù)使能系統(tǒng)函數(shù)pthread_create 創(chuàng)建處理任務(wù)的線程,在該線程內(nèi)首先進行系統(tǒng)函數(shù)pthread_detach 操作,使得該線程處理完任務(wù)后可以自動退出。
靜態(tài)線程池和動態(tài)線程池代碼組織方式基本一致,不同之處在于動態(tài)線程池多了線程池數(shù)量的動態(tài)調(diào)整過程。實際使用中的線程池通常與其他模塊深度結(jié)合,所以線程池的接口需要盡可能獨立。
(1)測試環(huán)境。FT-2000 處理器(4 核,2.6 GHz),內(nèi)存1 X 8 G/DDR4/2666 MHz/noECC/1.2 v, 銀河麒麟4.0.2。
(2)測試設(shè)計線程池相比原來多線程的機制優(yōu)勢主要體現(xiàn)在:節(jié)省線程的創(chuàng)建和銷毀時間以及能夠快速地將線程進行復(fù)用,但需考慮使用場景;任務(wù)并發(fā)量小,池內(nèi)的線程復(fù)用程度不高,能夠節(jié)省的少量線程的創(chuàng)建時間和銷毀時間,會被池內(nèi)線程的維護開銷所抵消;任務(wù)執(zhí)行時間很長,工作線程執(zhí)行任務(wù)的時間遠遠大于線程創(chuàng)建和調(diào)度的時間,那些短暫的時間不會帶來明顯的性能提升,因為線程池也需要進行部分維護工作。結(jié)合線程池常見的使用環(huán)境,將測試內(nèi)容定向到密集但耗時少的短任務(wù)上。測試對象是線程池對任務(wù)的平均響應(yīng)時間,任務(wù)派發(fā)方式為以一定時間T 為間隔,隨機產(chǎn)生任務(wù)數(shù)N添加到任務(wù)隊列直至任務(wù)數(shù)達到設(shè)定任務(wù)數(shù)M,其中以0 ~1 ms 之間的任意值作為時間間隔T,以10~50 個之間的任意值作為增加任務(wù)數(shù)N。分別與系統(tǒng)多線程方式和靜態(tài)線程池方式進行比較,使用50 個靜態(tài)線程與50 ~500 個動態(tài)線程池進行測試,測試結(jié)果如表1 所示。
表1 測試結(jié)果 ms
從上表的測試結(jié)果可以看出,當任務(wù)數(shù)越少時,處理任務(wù)的效率:多線程>靜態(tài)線程池>動態(tài)線程池;當任務(wù)數(shù)達到一定數(shù)量N時,處理任務(wù)的效率:靜態(tài)線程池>動態(tài)線程池>多線程;當任務(wù)數(shù)量遠遠超過N時,處理任務(wù)的效率:動態(tài)線程池>靜態(tài)線程池>多線程。
綜上所述,本文對多線程處理并發(fā)任務(wù)進行了概述,并提出了多線程、靜態(tài)線程池和動態(tài)線程池三種方案。針對動態(tài)線程池進行詳細設(shè)計,提出了線程回收方法和線程池參數(shù)調(diào)整方法,通過對方案進行代碼設(shè)計并進行不同數(shù)量的模擬任務(wù)進行測試。測試結(jié)果表明,在不同規(guī)模的任務(wù)量下,可以選擇不同的多線程方案,達到性能優(yōu)化的效果。目前絕大多數(shù)應(yīng)用都存在任務(wù)需求量大,潮汐不定等特性,因此動態(tài)線程池在提高任務(wù)響應(yīng)時間,提升用戶體驗等方面存在明顯優(yōu)勢。