1. 程式人生 > >【轉載】線程數究竟設多少合理

【轉載】線程數究竟設多少合理

key 如果 量化 增加 ket 生產 組件 操作 star

一、需求緣起

Web-Server通常有個配置,最大工作線程數,後端服務一般也有個配置,工作線程池的線程數量,這個線程數的配置不同的業務架構師有不同的經驗值,有些業務設置為CPU核數的2倍,有些業務設置為CPU核數的8倍,有些業務設置為CPU核數的32倍。

“工作線程數”的設置依據是什麽,到底設置為多少能夠最大化CPU性能,是本文要討論的問題。

二、一些共性認知

在進行進一步深入討論之前,先以提問的方式就一些共性認知達成一致。

提問:工作線程數是不是設置的越大越好?

回答:肯定不是的

1)一來服務器CPU核數有限,同時並發的線程數是有限的,1核CPU設置10000個工作線程沒有意義

2)線程切換是有開銷的,如果線程切換過於頻繁,反而會使性能降低

提問:調用sleep()函數的時候,線程是否一直占用CPU

回答:不占用,等待時會把CPU讓出來,給其他需要CPU資源的線程使用

不止調用sleep()函數,在進行一些阻塞調用,例如網絡編程中的阻塞accept()【等待客戶端連接】和阻塞recv()【等待下遊回包】也不占用CPU資源

提問:如果CPU是單核,設置多線程有意義麽,能提高並發性能麽?

回答:即使是單核,使用多線程也是有意義的

1)多線程編碼可以讓我們的服務/代碼更加清晰,有些IO線程收發包,有些Worker線程進行任務處理,有些Timeout線程進行超時檢測

2)如果有一個任務一直占用CPU資源在進行計算,那麽此時增加線程並不能增加並發,例如這樣的一個代碼

while(1){ i++; }

該代碼一直不停的占用CPU資源進行計算,會使CPU占用率達到100%

3)通常來說,Worker線程一般不會一直占用CPU進行計算,此時即使CPU是單核,增加Worker線程也能夠提高並發,因為這個線程在休息的時候,其他的線程可以繼續工作

三、常見服務線程模型

了解常見的服務線程模型,有助於理解服務並發的原理,一般來說互聯網常見的服務線程模型有如下兩種

IO線程與工作線程通過隊列解耦類模型

技術分享
如上圖,大部分Web-Server與服務框架都是使用這樣的一種“IO線程與Worker線程通過隊列解耦”類線程模型:

1)有少數幾個IO線程監聽上遊發過來的請求,並進行收發包(生產者)

2)有一個或者多個任務隊列,作為IO線程與Worker線程異步解耦的數據傳輸通道(臨界資源)

3)有多個工作線程執行正真的任務(消費者)

這個線程模型應用很廣,符合大部分場景,這個線程模型的特點是,工作線程內部是同步阻塞執行任務的(回想一下tomcat線程中是怎麽執行Java程序的,dubbo工作線程中是怎麽執行任務的),因此可以通過增加Worker線程數來增加並發能力,今天要討論的重點是“該模型Worker線程數設置為多少能達到最大的並發”。

純異步線程模型

任何地方都沒有阻塞,這種線程模型只需要設置很少的線程數就能夠做到很高的吞吐量,Lighttpd有一種單進程單線程模式,並發處理能力很強,就是使用的的這種模型。該模型的缺點是:

1)如果使用單線程模式,難以利用多CPU多核的優勢

2)程序員更習慣寫同步代碼,callback的方式對代碼的可讀性有沖擊,對程序員的要求也更高

3)框架更復雜,往往需要server端收發組件,server端隊列,client端收發組件,client端隊列,上下文管理組件,有限狀態機組件,超時管理組件的支持

however,這個模型不是今天討論的重點。

四、工作線程的工作模式

了解工作線程的工作模式,對量化分析線程數的設置非常有幫助:

技術分享
上圖是一個典型的工作線程的處理過程,從開始處理start到結束處理end,該任務的處理共有7個步驟:

1)從工作隊列裏拿出任務,進行一些本地初始化計算,例如http協議分析、參數解析、參數校驗等

2)訪問cache拿一些數據

3)拿到cache裏的數據後,再進行一些本地計算,這些計算和業務邏輯相關

4)通過RPC調用下遊service再拿一些數據,或者讓下遊service去處理一些相關的任務

5)RPC調用結束後,再進行一些本地計算,怎麽計算和業務邏輯相關

6)訪問DB進行一些數據操作

7)操作完數據庫之後做一些收尾工作,同樣這些收尾工作也是本地計算,和業務邏輯相關

分析整個處理的時間軸,會發現:

1)其中1,3,5,7步驟中【上圖中粉色時間軸】,線程進行本地業務邏輯計算時需要占用CPU

2)而2,4,6步驟中【上圖中橙色時間軸】,訪問cache、service、DB過程中線程處於一個等待結果的狀態,不需要占用CPU,進一步的分解,這個“等待結果”的時間共分為三部分:

2.1)請求在網絡上傳輸到下遊的cache、service、DB

2.2)下遊cache、service、DB進行任務處理

2.3)cache、service、DB將報文在網絡上傳回工作線程

五、量化分析並合理設置工作線程數

最後一起來回答工作線程數設置為多少合理的問題。

通過上面的分析,Worker線程在執行的過程中,有一部計算時間需要占用CPU,另一部分等待時間不需要占用CPU,通過量化分析,例如打日誌進行統計,可以統計出整個Worker線程執行過程中這兩部分時間的比例,例如:

1)時間軸1,3,5,7【上圖中粉色時間軸】的計算執行時間是100ms

2)時間軸2,4,6【上圖中橙色時間軸】的等待時間也是100ms

得到的結果是,這個線程計算和等待的時間是1:1,即有50%的時間在計算(占用CPU),50%的時間在等待(不占用CPU):

1)假設此時是單核,則設置為2個工作線程就可以把CPU充分利用起來,讓CPU跑到100%

2)假設此時是N核,則設置為2N個工作現場就可以把CPU充分利用起來,讓CPU跑到N*100%

結論:

N核服務器,通過執行業務的單線程分析出本地計算時間為x,等待時間為y,則工作線程數(線程池線程數)設置為 N*(x+y)/x,能讓CPU的利用率最大化。

經驗:

一般來說,非CPU密集型的業務(加解密、壓縮解壓縮、搜索排序等業務是CPU密集型的業務),瓶頸都在後端數據庫,本地CPU計算的時間很少,所以設置幾十或者幾百個工作線程也都是可能的。

六、結論

N核服務器,通過執行業務的單線程分析出本地計算時間為x,等待時間為y,則工作線程數(線程池線程數)設置為 N*(x+y)/x,能讓CPU的利用率最大化。

==【完】==

【轉自】58沈劍 架構師之路

【轉載】線程數究竟設多少合理