關於線程池ThreadPool的學習

  

  學習重點ThreadPool.SetMinThreads(out workerThreads, out completionPortThreads).這是整個線程池的關鍵。  而ThreadPool.SetMaxThreads(out workerThreads, out completionPortThreads)這個方法在你的線程總數低於1000時是不須要動它的。由於它的默認值就是1023,1000。而後在實際使用的時候只靠客戶端發大量線程來處理問題是不必定能下降實際執行時間的,有時候還和服務器端、數據庫有關係。數據庫

 

  首先談一下學習的背景,由於一箱貨裏有幾百件產品。用一條SQL語句來檢查這幾百件產品是否合格,搜索數據對比規格後出結果耗費的時間在7~12秒的時間。現場的操做環境是一箱一箱貨不停的掃描的。7~12秒的處理時間致使兩箱貨的掃描間隔達到10秒之多這是沒法接受的。在這種狀況下首先想到的是用多線程同時處理全部產品的數據。服務器

List<System.Threading.Thread> list = new List<System.Threading.Thread>();
                    foreach (DataRow row in ds.Tables[0].Rows)
                    {
                        //cellname = row[0].ToString();

                        System.Threading.Thread s1 = new System.Threading.Thread(QueryOCVTime);
                        list.Add(s1);
                        s1.Start(row[0].ToString());
                    }
                    bool IsOver = true;
                    while (IsOver)
                    {
                        for (int i = 0; i < list.Count; i++)
                        {
                            if (list[i].IsAlive)
                            {
                                System.Threading.Thread.Sleep(50);
                                break;
                            }
                            else if (i == (list.Count - 1))
                            {
                                IsOver = false;
                            }
                        }


                    }
代碼一Thread

  通過測試處理時間已經降到3~5秒了。可是離需求(1秒之內)還有很大的差距。並且也測試了單線程的執行時間才100毫秒,按邏輯來分析我幾乎是同時發出全部的單線程來執行,總的執行時間應該也是100毫秒左右。因此線程都是因此就想到了線程池多線程

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.Net;
using System.Threading;
namespace ConsoleApplication1
{
    class Program
    {
        private static List<string> list;
        private static DateTime dt1;
        static void Main(string[] args)
        {
            int maxworkthreads, maxportthreads, minworkthreads, minportthreads;
            Console.WriteLine("修改前");
            ThreadPool.GetMaxThreads(out maxworkthreads, out maxportthreads);
            ThreadPool.GetMinThreads(out minworkthreads, out minportthreads);          
            Console.WriteLine(maxworkthreads.ToString() + "\t" + maxportthreads.ToString());
            Console.WriteLine(minworkthreads.ToString() + "\t" + minportthreads.ToString());
            //public static bool SetMinThreads(int workerThreads, int completionPortThreads);
            //最關鍵的修改參數   
            //workerThreads
            //這個值決定了同時執行的最大線程數,超過這個數量就要排隊。
            //這個值不是越大越好,要綜合考慮單線程在進行什麼樣的操做。          
            ThreadPool.SetMinThreads(500, minportthreads);
            Console.WriteLine("修改後");
            ThreadPool.GetMaxThreads(out maxworkthreads, out maxportthreads);
            ThreadPool.GetMinThreads(out minworkthreads, out minportthreads);
            Console.WriteLine(maxworkthreads.ToString() + "\t" + maxportthreads.ToString());
            Console.WriteLine(minworkthreads.ToString() + "\t" + minportthreads.ToString());
            list = new List<string>();
            dt1 = DateTime.Now;
            for (int i = 0; i < 100; i++)
            {
                //開始執行單線程
                ThreadPool.QueueUserWorkItem(new WaitCallback(RunThread), i.ToString());
            }

            bool IsOver = true;
            while (IsOver)
            {
                //檢測全部單線程是否執行完畢
                int maxthreads, threads, workthreads;
                ThreadPool.GetMaxThreads(out maxthreads, out threads);
                ThreadPool.GetAvailableThreads(out workthreads, out threads);               
                if ((maxthreads - workthreads) == 0)
                {
                    IsOver = false;
                }
                else
                {
                    Thread.Sleep(100);
                }
            }
            DateTime dt2 = DateTime.Now;
            //運行完畢將執行過程打印出來以便於分析
            for (int i = 0; i < list.Count; i++)
            {
                Console.WriteLine(list[i]);
            }       

            Console.WriteLine("流程已經運行完畢一共耗時{0}", (dt2 - dt1).TotalSeconds.ToString("0.000"));

            Console.ReadKey();
        }
        private static void RunThread(object obj)
        {

            DateTime dt2 = DateTime.Now;
            //假定單線程的處理時間是800毫秒
            Thread.Sleep(800);
            DateTime dt3 = DateTime.Now;
            //記錄下線程和執行時間的信息到後面再打印出來,以避免執行時間在打印時浪費而影響測試結果
            list.Add(string.Format("{0},thread {1}\t,啓動時間{2},耗時 {3},總耗時 {4}",
                                                                        obj.ToString(),
                                                                        Thread.CurrentThread.ManagedThreadId,
                                                                         (dt2 - dt1).TotalSeconds.ToString("0.000"),
                                                                        (dt3 - dt2).TotalSeconds.ToString("0.000"),
                                                                        (dt3 - dt1).TotalSeconds.ToString("0.000")
                                     )
                      );

        }
    }
}
View Code ThreadPool

 「public static bool SetMinThreads(int workerThreads, int completionPortThreads);」。這個SetMinThreads(out workerThreads, out completionPortThreads)方法是整個線程池的關鍵。WorkThreads是指最大活動線程數(便可同時執行的最大線程數),completionPortThreads是指最大IO線程數(便可同時執行的最大IO)。WorkThreads的大小影響整個流程的結束時間,若是單個線程須要10毫秒才能執行完,一共有10個線程而且把WorkThreads設置爲5,那麼整個流程的完成時間在20毫秒左右。便是單個線程的2倍時間。即執行時間=總線程數/WorkThreads * 單流程時間。ide

  這段測試代碼的執行結果是很是理想的。學習

  98,thread 107 ,啓動時間0.219,耗時 0.801,總耗時 1.020測試

  99,thread 108 ,啓動時間0.225,耗時 0.801,總耗時 1.026spa

  流程已經運行完畢一共耗時1.11線程

可是在將這段代碼移植到實際狀況中時結果使人很沮喪。仍然仍是要2~3秒才能出結果。仔細查看輸出結果不難發現其中的問題code

1,thread 6 ,啓動時間0.247,耗時 0.309,總耗時 0.556orm

2,thread 22 ,啓動時間0.270,耗時 0.291,總耗時 0.561

......

39,thread 53 ,啓動時間0.372,耗時 1.389,總耗時 1.761

40,thread 55 ,啓動時間0.372,耗時 1.394,總耗時 1.766

......

50,thread 61 ,啓動時間0.374,耗時 1.610,總耗時 1.984

63,thread 63 ,啓動時間0.373,耗時 1.677,總耗時 2.050

從上面的輸出結果能夠看出來在實際的使用環境中,雖然全部線程的啓動時間相差是不大的,可是執行時間相差太多了從第1個線程才0.309秒到最後一個線程達到了1.677秒。代表同時執行的線程越多,到後面的線程執行的效率就越慢。致使最後的總執行時間就超出咱們的預期了。

這裏致使執行效率慢的緣由已經再也不是線程的問題了。而有多是數據庫的IO或服務器的IO有限制。客戶端同時發出大量的請求查找數據,可是在服務端或者在數據庫這些同時發出來的線程出現排隊的狀況了。這個結論是我通過大量測試後得出來的,在後期若是有條件再來驗證這個想法。

相關文章
相關標籤/搜索