[C#.NET][Thread] 執行緒集區 – ThreadPool

[C#.NET][Thread] 執行緒集區 – ThreadPool

看了安德魯的文章,可以讓人裡解ThreadPool背後在玩的把戲 ThreadPool 實作 #1. 基本概念,絕對會讓您收獲不少。

執行緒集區會維持一個最小閒置執行緒數目,當使用ThreadPool.QueueUserWorkItem方法時會喚醒正在休眠的執行緒,這樣一來就比我們不斷直接使用Thread類別重新建立執行緒還要來的節省資源一點,執行緒集區內的執行緒工作滿檔時,會再自動增加執行緒的數量。

另外MSDN有提到,

如果應用程式受到突然增加的活動影響 (例如,大量佇列的執行緒集區工作),請使用 SetMinThreads 方法增加最小閒置執行緒的數目。否則,建立新閒置執行緒時的內建延遲可能會造成瓶頸。

這表示若有需要大量執行緒數量要增加時,反而會因為這些延遲而拖垮系統,保哥也是曾經受到它的荼毒 ,使用 ThreadPool 時應注意預設同時執行的 Thread 數量 

ThreadPool.QueueUserWorkItem方法需要傳入一個WaitCallback委派,這個委派的簽名是

public delegate void WaitCallback (
    Object state
)
所以只要建立跟它有相同簽名的方法,就可以建立WaitCallback委派了。
ThreadPool.QueueUserWorkItem方法只有兩種多載,除了固定要傳WaitCallback委派,另一個參數就是object物件,所以表示我們可以傳很大的東西進去DoWorker(object number)方法裡
static void Main(string[] args)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(DoWorker), i);
    ThreadPool.QueueUserWorkItem(new WaitCallback(DoWorker));
}

static void DoWorker(object number)
{
    //TODO..
}

先來看看簡單的使用範例

傳入一個參數

static void Main(string[] args)
{
    for (int i = 0; i < 10; i  )
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(DoWorker), i);
    }
    Console.WriteLine("Main thread exit");
    Console.ReadKey();
}
static void DoWorker(object number)
{
    Thread t = Thread.CurrentThread;
    Console.WriteLine("No.{0}-Thread[{1}]:{2}", number, t.ManagedThreadId, t.ThreadState);
    Thread.Sleep(1000);
}

因為閒置的執行緒被喚醒,所以可以看到,有許多重複的執行緒會出現

 

傳入多個參數

若需要傳入不只一個參數,我們可以利用類別(class)或結構(struct)來傳入,當然你也可以傳入集合…反正你想的到的資料型態什麼都能傳,只要再DoWorker方法裡記得轉型就可以了。

static void Main(string[] args)
{
    Book book = new Book();
    book.author = "余小章";
    book.price = 1000;
    book.title = "MVP";
    ThreadPool.QueueUserWorkItem(new WaitCallback(DoWorker), book); 

    Console.WriteLine("Main thread exit");
    Console.ReadKey();
}
static void DoWorker(object book)
{
    Thread t = Thread.CurrentThread;
    Book b = (Book)book;
    Console.WriteLine("Thread[{0}]:{1}", t.ManagedThreadId, t.ThreadState);
    Console.WriteLine("author:{0},title{1},price:{2}", b.author, b.title, b.price); 

    Thread.Sleep(1000);
}
public struct Book
{
    public decimal price;
    public string title;
    public string author;
}