王 鑫,扈 月,劉坤禹,王歡歡,甄帥輝
(1 中國電子科技集團公司第三十研究所 四川 成都 610041)
(2 中國人民解放軍31012 部隊 北京 100091)
線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位[1]。多線程技術主要解決任務并發的問題,它的核心在于將宏觀的任務量拆解為微觀的任務分量,將任務分量派發到不同的線程上,從而減少任務的處理時間。多線程使用場景一般分為兩種:第一種為按需分配,即針對每個任務派生一個獨立的線程去處理該任務,雖然在任務量少的應用中,該方式處理效率高,但是在任務量巨大的應用中,該方式在線程創建和銷毀中將耗費大量時間;第二種為預先分配,即提前創建包含一定數目線程的線程池,線程池又分為靜態線程池和動態線程池兩種,靜態線程池通過預先創建包含固定數量線程的線程池去處理任務,動態線程池相較于靜態線程池的不同點在于可以通過任務量的變化動態調整線程池中線程的數量,它們都能節省線程的創建和銷毀時間,從而降低每個線程的平均創建和銷毀時間。
靜態線程池預先創建一定數量線程后,線程數量不再變化,用以處理所有任務,但當任務達到波峰時,任務響應時間將會加大,降低用戶體驗感。動態線程池也是預先創建一定數量線程后,通過對任務量的分析,動態調整線程池中線程數量的大小,降低任務響應時間。動態線程池實現時面臨一些問題,例如動態調整線程池系數不恰當和單個工作線程如何回收銷毀。
本文將對以上提出的三種多任務處理模型進行分析,并著重優化設計動態線程池,通過不同規模的模擬任務,不同模型參數的調整,對比驗證三種模型。
多線程方案即“隨時請求,隨時創建,隨時回收”,任務請求送入任務調度模塊,任務調度模塊創建線程進行任務請求處理,任務處理完畢后,線程回收模塊進行線程的回收和銷毀,面對多少任務,即需創建多少個線程進行任務處理。
該方案邏輯簡單,實現便捷,適用于小規模且無周期性的任務量。但是當任務量爆發式增長時,該方案受限于操作系統和硬件資源所能創建的線程數總量,當線程數達到上限后,新來的任務將不能得到及時處理[2]。
靜態線程池方案即“預先創建,隨時請求,統一回收”,初始化模塊創建預先設定數量M 的線程,當出現任務請求,通過任務入隊模塊將任務存入任務隊列中,線程池從任務隊列中獲取任務,進行任務處理,線程池的數量始終保持不變。方案示意如圖1 所示。

圖1 靜態線程池方案示意圖
針對一定規模且周期性的任務量,利用靜態線程池的方案,可以節省線程創建和銷毀的時間,加快任務處理速度,提升用戶體驗感。當任務量達到線程池的數量M 后,沒有新的線程可以處理任務隊列中的任務,會加大一些任務的處理時間,降低用戶體驗感。
動態線程池方案即“動態創建,隨時請求,動態回收”。初始化模塊創建預先設定數量的線程,當出現任務請求,通過任務入隊模塊將任務存入任務隊列中,線程池從任務隊列中獲取任務,進行任務處理。當任務監控模塊檢測到線程池空閑線程數量在設定的時間T1 內一直為0且任務隊列中的任務數量不為0,任務監控模塊將根據調整系數P1 進行新線程的創建;當任務監控模塊檢測到線程池空閑線程數量在設定時間T2 內一直不為0 且任務隊列中的任務數據為0,任務監控模塊將根據調整系數P2進行空閑線程的回收。方案示意如圖2 所示。

圖2 動態線程池方案示意圖
針對一定規模、周期性、具有井噴式特性的任務量,利用動態線程池的方案,不僅可以節省線程創建和銷毀的時間,而且當任務量井噴式地增長時,可以動態調整線程數量,加快任務處理速度,提升用戶體驗感。當任務量經過潮汐趨于平穩時,通過銷毀線程池中空閑的線程,確保線程池的活性[3]。該方案的難點主要為如何確定線程池動態調整的系數,如何高效回收空閑線程。
因多線程方案和靜態線程池方案邏輯和結構簡單,因此下面主要針對動態線程池進行分析與設計。
傳統動態線程池采用“動態創建,隨時請求,動態回收”的方式對線程池進行控制,其中動態調整線程池線程數和線程池的空閑線程安全退出機制的選擇對動態線程池的性能起著關鍵作用。本文主要針對以上兩點進行分析與設計。
針對動態調整線程數,傳統的做法為基于預測公式進行線程數調整,該方法實現復雜,且使用場景具有局限性[4]。
固定線程數量的線程池在某些場景下不能滿足應用需求,線程池常見的動態調整線程數量的方案有基于設定值觸發和基于任務量趨勢預測兩種形式:①基于任務量趨勢預測的方式對任務建模要求高,需要結合統計學原理進行任務量趨勢預測,能夠真實反映任務量的變化從而進行高效處理,但是該方式的使用場景具有局限性,且需要較大的算力資源;②基于設定值觸發的方式通過預先設置不同規模的參數集合,通過任務量的跟蹤選擇合適的參數,實現簡單,線程池維護開銷小且通用性較高。本文為保證線程池的通用性,采用基于設定值觸發方式來動態調整線程池。
(1)合理設置相關參數
若設線程池中最大線程數為T_MAX,最小線程數為_MIN,最大空閑線程數為T_FMAX,最小空閑線程數為T_FMIN,處理原則是:①在線程池初始化階段,創建T_MIN個空閑線程。②線程池中空閑線程數量T_FNOW 低于T_FMIN 時,通過待處理任務量派生調整系數P1 觸發線程池調整進行P1×T_MIN 個線程添加。③線程池中空閑線程數量T_FNOW 不低于T_FMIN 且小于T_FMAX 時,通過固定調整系數P2 觸發線程池調整進行P2×(T_FNOWTFMIN)個線程刪除。④線程池中空閑線程數量不低于T_FMAX 時,通過固定調整系數P3 觸發線程池調整進行P2×(T_FNOW-TFMAX)個線程刪除。⑤調整過程中保證調整后的線程池線程數量小于T_MAX 且大于等于T_MIN。
(2)延遲銷毀線程
在任務量激增的情況下通過設定值觸發增加一定數量的線程后,當任務量減少時,需要銷毀這部分創建的線程。此時并不真正地銷毀這些線程,而是將它放入銷毀列表中,創建并使能定時器。當定時器計時完畢時,若無創建新線程的需求將會銷毀這些線程;如果在定時器計時完畢前,有創建新線程的需求,將刪除該銷毀列表的定時器,并使用這些還未銷毀的線程,根據任務量變化重復前面的步驟,從而達到了提高線程的復用。
針對空閑線程安全退出,傳統的做法為在線程創建初期進行統計,并對創建的線程進行狀態監控,當需要減少線程數量時,通過狀態監控發現空閑線程并進行回收,該方法存在的問題為對線程進行狀態監控將耗費大量計算資源[5]。
線程退出的方式主要分為線程主動退出和線程被動退出兩種,多線程方案和靜態線程池方案不需要考慮線程退出的方式,直接進行線程回收即可。動態線程池方案需要考慮線程回收的方式,需檢測線程池中的線程是否處于空閑狀態。一般采用輪詢或者信號觸發,輪詢即重復地查詢某個線程的狀態,將會耗費大量的計算資源;信號量方式需要維護大量的信號量,耗費大量的存儲資源。
因此本文提出一種空閑自動釋放機制,當任務監控模塊做出決策應減少線程數量時,將“自殺”任務放入任務隊列中,此時空閑線程便無差別地從任務隊列中領取任務,從而釋放資源,結束線程。
多線程方案即一任務一線程,用完即毀,使用操作系統自帶函數即可實現。
本文通過添加函數等實現了線程池創建、初始化、獲取線程數量和獲取線程池狀態等接口,通過對該系列接口的動態組合,可以實現靜態線程池和動態線程池兩種方案。
(1)使用方法

(2)接口與功能
采用面向對象的思想,將線程池的方法定義在sl_thread_pool 結構體中,實現線程池的初始化、狀態查詢和線程數量調整等功能。

針對多線程方案,通過任務使能系統函數pthread_create 創建處理任務的線程,在該線程內首先進行系統函數pthread_detach 操作,使得該線程處理完任務后可以自動退出。
靜態線程池和動態線程池代碼組織方式基本一致,不同之處在于動態線程池多了線程池數量的動態調整過程。實際使用中的線程池通常與其他模塊深度結合,所以線程池的接口需要盡可能獨立。
(1)測試環境。FT-2000 處理器(4 核,2.6 GHz),內存1 X 8 G/DDR4/2666 MHz/noECC/1.2 v, 銀河麒麟4.0.2。
(2)測試設計線程池相比原來多線程的機制優勢主要體現在:節省線程的創建和銷毀時間以及能夠快速地將線程進行復用,但需考慮使用場景;任務并發量小,池內的線程復用程度不高,能夠節省的少量線程的創建時間和銷毀時間,會被池內線程的維護開銷所抵消;任務執行時間很長,工作線程執行任務的時間遠遠大于線程創建和調度的時間,那些短暫的時間不會帶來明顯的性能提升,因為線程池也需要進行部分維護工作。結合線程池常見的使用環境,將測試內容定向到密集但耗時少的短任務上。測試對象是線程池對任務的平均響應時間,任務派發方式為以一定時間T 為間隔,隨機產生任務數N添加到任務隊列直至任務數達到設定任務數M,其中以0 ~1 ms 之間的任意值作為時間間隔T,以10~50 個之間的任意值作為增加任務數N。分別與系統多線程方式和靜態線程池方式進行比較,使用50 個靜態線程與50 ~500 個動態線程池進行測試,測試結果如表1 所示。

表1 測試結果 ms
從上表的測試結果可以看出,當任務數越少時,處理任務的效率:多線程>靜態線程池>動態線程池;當任務數達到一定數量N時,處理任務的效率:靜態線程池>動態線程池>多線程;當任務數量遠遠超過N時,處理任務的效率:動態線程池>靜態線程池>多線程。
綜上所述,本文對多線程處理并發任務進行了概述,并提出了多線程、靜態線程池和動態線程池三種方案。針對動態線程池進行詳細設計,提出了線程回收方法和線程池參數調整方法,通過對方案進行代碼設計并進行不同數量的模擬任務進行測試。測試結果表明,在不同規模的任務量下,可以選擇不同的多線程方案,達到性能優化的效果。目前絕大多數應用都存在任務需求量大,潮汐不定等特性,因此動態線程池在提高任務響應時間,提升用戶體驗等方面存在明顯優勢。