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