執行緒池基礎 ThreadPool基礎

2022-01-11 06:50:53 字數 3226 閱讀 7728

池(pool)是乙個很常見的提高效能的方式。比如執行緒池連線池等,之所以有這些池是因為執行緒和資料庫連線的建立和關閉是一種比較昂貴的行為。對於這種昂貴的資源我們往往會考慮在乙個池容器中放置一些資源,在用的時候去拿,在不夠的時候添點,在用完就歸還,這樣就可以避免不斷的建立資源和銷毀資源。

如果您做過相關實驗的話可能會覺得不以為然,似乎開1000個執行緒也用不了幾百毫秒。我們要這麼想,對於乙個高併發的環境來說,每一秒假設有100 個請求,每個請求需要使用(開和關)10個執行緒,也就是一秒需要處理1000個執行緒的開和關,每個執行緒獨立堆疊1m,可以想象在這一秒中記憶體分配和**是多麼誇張,這個開銷不能說不昂貴。

首先,要理解執行緒池執行緒分為兩類工作執行緒和io執行緒,可以單獨設定最小執行緒數和最大執行緒數:

threadpool.setminthreads(2, 2);

threadpool.setmaxthreads(4, 4);

最大執行緒數很好理解,就是執行緒池最多建立這些執行緒,如果最大4個執行緒,現在這4個執行緒都在執行的話,後續進來的執行緒只能排隊等待了。那麼為什麼有最小執行緒一說法呢?其實之所以使用執行緒池是不希望執行緒在建立後執行結束後理解**,這樣的話以後要用的時候還需要建立,我們可以讓執行緒池至少保留幾個執行緒,即使沒有執行緒在工作也保留。上述語句我們設定執行緒池一開始就保持2個工作執行緒和2個io執行緒,最大不超過4個執行緒。

至於執行緒池的使用相當簡單先來看一段**:

for (int i = 0; i < totalthreads; i++)

/) # : ", a, b, thread.currentthread.managedthreadid, datetime.now.tostring("mm:ss")));

});}

console.writeline("main thread finished");

console.readline();

**裡面用到了乙個事先定義的靜態字段:

static readonly int totalthreads = 10;

**執行結果如下:

每乙個執行緒都休眠一秒然後輸出當前執行緒池可用的工作執行緒和io執行緒以及當前執行緒的託管id和時間。我們通過這段**可以發現執行緒池的幾個特性:

1) 執行緒池中的執行緒都是後台執行緒,如果沒有在主線程使用readline的話,程式馬上會退出。

2) 執行緒池一開始就占用了2個執行緒,一秒後占用了4個執行緒,工作執行緒將會由3-6四個執行緒來處理。

3) 執行緒池最多使用了4個工作執行緒和0個io執行緒。

那麼,我們如何知道執行緒池中的執行緒都執行結束了呢,可以想到上文用過的monitor結構:

stopwatch sw = stopwatch.startnew();

for (int i = 0; i < totalthreads; i++)

/) # : ", a, b, thread.currentthread.managedthreadid, datetime.now.tostring("mm:ss")));

lock (locker)

});}

lock (locker)

console.writeline(sw.elapsedmilliseconds);

console.readline();

程式中用到了兩個輔助字段:

static object locker = new object();

static int runningthreads = totalthreads;

程式執行結果如下:

我們看到,10個執行緒使用了3.5秒全部執行完畢。20個執行緒呢?  

需要6秒。細細分析這2個圖我們不難發現,新的執行緒不是在不夠用的時候立即建立而是延遲了0.5秒左右的時間,這是因為執行緒池會等待一下看是不是有執行緒在這段時間內可用,如果實在沒有的話再建立。其實可以這麼理解這6秒,前一秒只有2個執行緒,後4秒有4個執行緒執行了16個,最後1秒又只有2個執行緒了,所以一共是2+4*4+2=20,6秒處理了20個執行緒。

首先定義訊號量和儲存結果的字段:

static manualresetevent mre = new manualresetevent(false);

static int result = 0;

程式如下:

stopwatch sw = stopwatch.startnew();

for (int i = 0; i < totalthreads; i++)

/) # : ", a, b, thread.currentthread.managedthreadid, datetime.now.tostring("mm:ss")));

lock (locker)

}, null, 500, true);

}thread.sleep(1000);

result = 10;

mre.set();

lock (locker)

console.writeline(sw.elapsedmilliseconds);

console.writeline(result);

console.readline();

第乙個引數就是訊號量,第二個引數就是方法主體(接受兩個引數分別是傳給執行緒的乙個狀態變數以及執行緒執行的時候是否超時),第三個引數是狀態變數,第四個引數超時時間我們設定了500毫秒,由於主線程在1秒後發出訊號,超時500毫秒,所以這些執行緒並沒等到訊號的發出500毫秒之後就執行了。之所以程式的執行結果為30是因為即使500毫秒之後執行緒超時開始執行但是也要等1秒才累加結果,在這個時候主線程早已把結果更新為10了,所以累加從10開始而不是0開始。最後布林引數為true表明接受到訊號後只執行緒執行一次。

觀察到,所有執行緒執行完畢花了7秒的時間,除去開始的等待時間0.5秒,相比之前的例子還多了0.5秒的時間。這是為什麼呢?請大家幫忙分析分析。還有乙個更奇怪的問題是,registerwaitforsingleobject消耗的是io執行緒而不是工作執行緒,難道微軟覺得 registerwaitforsingleobject常見於io操作的應用還是不希望不浪費工作執行緒?

執行緒池 Thread Pool

烽驛2009開源實時通訊平台 原始碼獲取 svn checkouthttp fy2009.googlecode.com svn trunk fy2009 read only 眾所周知,執行緒並非越多越好,理論上乙個cpu 或core 乙個活動執行緒可獲得最佳效能。執行緒池可根據具體硬體的情況 如cp...

ThreadPool(執行緒池)

任務後台基礎 執行緒池。建立執行緒需要時間。如果有不同的短任務要完成,就可以事先建立許多執行緒,在應完成這些任務時發出請求,這個執行緒最好在需要更多的執行緒時增加,在需要釋放資源時減少。不需要自己建立這樣的乙個列表,該錶由threadpool類託管,這個類會在需要時增減池中線程的執行緒數,直到達到最...

ThreadPool 執行緒池

最近在做通訊的專案,裡面需要使用點執行緒池,這裡做下筆記,歡迎指點!執行緒池功能 應用程式可以有多個執行緒,net框架為每個程序提供了乙個執行緒池,乙個執行緒池有若干個等待操作狀態,當乙個等待操作完成時,執行緒池中的輔助線程會執行 函式。執行緒池中的執行緒由系統管理,程式設計師不需要費力於執行緒管理...