執行緒池 合理的設定大小

2021-09-29 05:18:04 字數 2727 閱讀 3827

直接建立大量執行緒的壞處

對於乙個web伺服器,伺服器應用程式會處理來自客戶端的請求。假設,每到達乙個請求,我們的程式都為該請求建立乙個執行緒來執行請求任務,那麼這個建立的執行緒數目將會是無窮無盡的,「為每乙個請求任務分配乙個執行緒」,該做法是存在一些缺陷的,尤其是建立大量執行緒時:

(1)執行緒的生命週期的開銷高:我們要明白執行緒的建立和銷毀是需要代價的,如果說客戶端請求的任務是很輕量級的,往往這種任務所執行的時間都很短並且做的事也很簡單,那麼為每乙個請求建立執行緒,會消耗大量的計算機資源的。

(2)資源的消耗:乙個活躍的執行緒會消耗系統的資源,特別是記憶體。當建立的執行緒太多時並且多過了cpu的核心數,必定會有執行緒會閒置。當大量執行緒閒置時,會占用大量的記憶體(極有可能會造成oom異常),而且這麼多的執行緒之間也會因為cpu的不足而存在競爭(執行緒經常得在使用者態和核心態之間轉換需要開銷),所以當你的執行緒數如果達到了剛好使cpu處於忙碌,那麼這時繼續建立新執行緒,反而會降低效能。

執行緒池的作用

執行緒池作用就是限制系統中執行執行緒的數量。

根據系統的環境情況,可以自動或手動設定執行緒數量,達到執行的最佳效果;少了浪費了系統資源,多了造成系統擁擠效率不高。用執行緒池控制線程數量,其他執行緒排隊等候。乙個任務執行完畢,再從佇列的中取最前面的任務開始執行。若佇列中沒有等待程序,執行緒池的這一資源處於等待。當乙個新任務需要執行時,如果執行緒池中有等待的工作執行緒,就可以開始執行了;否則進入等待佇列。

為什麼要用執行緒池:

(1)減少了建立和銷毀執行緒的次數,每個工作執行緒都可以被重複利用,可執行多個任務。

(2)可以根據系統的承受能力,調整執行緒池中工作線執行緒的數目,防止因為消耗過多的記憶體,而把伺服器累趴下(每個執行緒需要大約1mb記憶體,執行緒開的越多,消耗的記憶體也就越大,最後宕機)。

那麼在建立執行緒池時,我們又該如何設定好執行緒池的大小呢?

首先,設定乙個執行緒池之前,我們先要知道執行緒所執行的任務,都是有不同的執行策略的:

(1)依賴性任務:大多數的任務都是不依賴於其他任務所執行的時序、時長、執行結果,但是如果乙個任務執行需要依賴於其他的任務,那麼該任務可以被認為是有依賴性的。

(2)執行緒封閉的任務:該任務在執行時,其他任務都不能執行,適合單執行緒池。

(3)響應時間敏感的任務:在上面的執行緒封閉任務,如果乙個執行時間很長的任務交給單執行緒池去做,那麼很長時間才會得到反饋,,所以時間敏感的任務不適合單執行緒模式。

對於依賴性很強的任務,要時刻注意執行緒池裡的執行緒數目不能過小,因為執行緒數如果不夠,a任務所依賴的b任務可能就要被放入等待佇列,那麼此時a任務就很可能執行不下去,最極端的情況可能就是b此時正好需要a任務所占用的執行緒,這時就會導致「執行緒飢餓死鎖」。

那麼如何設定執行緒池大小?

性質不同的任務可以交給不同規模的執行緒池執行。

任務的性質:

(1)cpu密集型

(2)i/o密集型

(3)混合型任務

對於不同性質的任務來說,cpu密集型任務應配置盡可能小的執行緒,因為如果為cpu密集型的任務開啟太多的執行緒,那麼cpu為了排程好這些執行緒會消耗太多資源。而io密集型任務應配置盡可能多的執行緒,因為io操作不占用cpu,所以儘管執行緒比較多,cpu也不用為了排程執行緒而花費太多開銷,所以可以加大執行緒數量(但是也別太多)。

若任務對其他系統資源有依賴,如某個任務依賴資料庫的連線返回的結果,這時候等待的時間越長,則cpu空閒的時間越長,那麼執行緒數量應設定得越大,這樣cpu就會去處理其他的執行緒,所以才能更好的利用cpu。 

當然具體合理執行緒池值大小,需要結合系統實際情況,在大量的嘗試下比較才能得出,以上只是前人總結的規律。

最佳執行緒數目 = ((執行緒等待時間+執行緒cpu時間)/執行緒cpu時間 )* cpu數目
比如平均每個執行緒cpu執行時間為0.5s,而執行緒等待時間(非cpu執行時間,比如io)為1.5s,cpu核心數為8,那麼根據上面這個公式估算得到:((0.5+1.5)/0.5)*8=32。這個公式進一步轉化為:

最佳執行緒數目 = (執行緒等待時間與執行緒cpu時間之比 + 1)* cpu數目
總結: 

執行緒等待時間所佔比例越高(執行緒此時很可能在等待依賴性任務完成或者處於io阻塞,此時不佔cpu,所以應該建立更多的執行緒讓空閒的cpu去處理),需要越多執行緒。執行緒cpu時間所佔比例越高,需要越少執行緒。

高併發、任務執行時間短的業務怎樣使用執行緒池?併發不高、任務執行時間長的業務怎樣使用執行緒池?併發高、業務執行時間長的業務怎樣使用執行緒池? 

(1)高併發、任務執行時間短的業務:因為時間短,很可能就是cpu密集型,所以執行緒不宜過多,和cpu核心數差不多就好。

(2)併發不高、任務執行時間長的業務要區分開看: 

a)假如是業務時間長集中在io操作上,也就是io密集型的任務,因為io操作並不占用cpu,所以不要讓所有的cpu閒下來,可以適當加大執行緒池中的執行緒數目,讓cpu處理更多的業務 。

b)假如是業務時間長集中在計算操作上,也就是計算密集型任務,這個就沒辦法了,和(1)一樣吧,執行緒池中的執行緒數設定得少一些,減少執行緒上下文的切換 。

(3)併發高、任務執行時間又長,解決這種型別任務的關鍵不在於執行緒池而在於整體架構的設計,看看這些業務裡面某些資料是否能做快取是第一步,增加伺服器是第二步,至於執行緒池的設定,設定參考(2)。最後,業務執行時間長的問題,也可能需要分析一下,看看能不能使用中介軟體對任務進行拆分和解耦。

如何合理設定執行緒池大小

要想合理的配置執行緒池的大小,首先得分析任務的特性,可以從以下幾個角度分析 任務的性質 cpu密集型任務 io密集型任務 混合型任務。任務的優先順序 高 中 低。任務的依賴性 是否依賴其他系統資源,如資料庫連線等。性質不同的任務可以交給不同規模的執行緒池執行。對於不同性質的任務來說,cpu密集型任務...

如何合理設定執行緒池大小

這個問題雖然看起來很小,卻並不那麼容易回答。大家如果有更好的方法歡迎賜教,先來乙個天真的估算方法 假設要求乙個系統的tps transaction per second或者task per second 至少為20,然後假設每個transaction由乙個執行緒完成,繼續假設平均每個執行緒處理乙個t...

如何合理設定執行緒池大小

要想合理的配置執行緒池的大小,首先得分析任務的特性,可以從以下幾個角度分析 任務的性質 cpu密集型任務 io密集型任務 混合型任務。任務的優先順序 高 中 低。任務的依賴性 是否依賴其他系統資源,如資料庫連線等。性質不同的任務可以交給不同規模的執行緒池執行。對於不同性質的任務來說,cpu密集型任務...