1. 程式人生 > 實用技巧 >多執行緒系列(三)之執行緒池

多執行緒系列(三)之執行緒池

什麼是執行緒池?

.NetFramework1.0時代的Thread,API功能繁多,對執行緒的數量是沒有管控的,在.NetFramework2.0時代推出了ThreadPool,如果某個物件建立和銷燬代價比較高,同時這個物件還可以反覆使這些執行緒,就需要使用執行緒池,執行緒池可以儲存多個執行緒物件,需要使用執行緒時直接從執行緒池裡面拿,使用完之後不做釋放,又放回池子(享元模式),需要用的時候再去拿。這樣可以減少建立執行緒的開銷,提升效能,此外,還可以管控執行緒的總數量,防止資源濫用。

委託非同步呼叫、Task、Parrallel、async/await的執行緒全部都是執行緒池裡面的執行緒。直接new Thread開起的執行緒不受執行緒池的數量限制(但是會佔用執行緒池的執行緒數量)。

使用執行緒池開啟執行緒

            ThreadPool.QueueUserWorkItem(o=>this.DoSomeThing("btnThreadPool_Click_1"));
            ThreadPool.QueueUserWorkItem(o => {
                this.DoSomeThing("btnThreadPool_Click_2");
                Console.WriteLine( o?.ToString());
            }, "wjl");

檢索和設定執行緒池的最大最小數目和非同步IO執行緒的最大最小數目

I/O執行緒是.NET專為訪問外部資源所設定的一種執行緒,因為訪問外部資源常常要受到外界因素的影響,為了防止讓主執行緒受影響而長期處於阻塞狀態,.NET為多個I/O操作都建立起了非同步方法。

            //檢索由 GetMaxThreads 返回的執行緒池執行緒的最大數目和非同步IO執行緒的最大數目
            ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
            Console.WriteLine($"當前執行緒池最大數目為:{workerThreads},最大非同步IO執行緒:{completionPortThreads}
"); //檢索由 GetMinThreads 返回的執行緒池執行緒的最小數目和非同步IO執行緒的最小數目 ThreadPool.GetMinThreads(out int workerThreadsMin, out int completionPortThreadsMin); Console.WriteLine($"當前執行緒池最小數目為:{workerThreadsMin},最小非同步IO執行緒:{completionPortThreadsMin}"); ThreadPool.SetMaxThreads(8, 8);//設定的最大值,必須大於CPU核數,否則設定無效 ThreadPool.SetMinThreads(2, 2);

執行緒等待

單個執行緒等待:

                //執行緒等待
                ManualResetEvent mre = new ManualResetEvent(false);
                //ManualResetEvent是一種訊號量的方式
                //如果初始為false--關閉, mre.Set()之後變為ture,WaitOne就能通過
                //如果初始為tue--開啟, mre.Rset()之後變為false,WaitOne就只能等待
                ThreadPool.QueueUserWorkItem(o => {
                    this.DoSomeThing("btnThreadPool_Click_3");
                    mre.Set();
                });
                mre.WaitOne();
                Console.WriteLine("任務已經完成了...");

多個執行緒等待:

                ManualResetEvent[] mres = new ManualResetEvent[10];
                for (int i = 0; i < 10; i++)
                {
                    mres[i] = new ManualResetEvent(false);
                    int k = i;
                    ThreadPool.QueueUserWorkItem(o =>
                    {
                        this.DoSomeThing($"mres{k}");
                        ManualResetEvent mre = o as ManualResetEvent;
                        mre.Set();
                    }, mres[i]);
                }
                //等待所有陣列中的元素都收到訊號,如果是控制檯程式或者winform程式,請將Main()函式上面的特性[STAThread]註釋掉
                WaitHandle.WaitAll(mres);
                Console.WriteLine("多個任務已經完成了...");