抓蟲系列(四) 不要輕視web程序中常用的三個"池" 之線程池

前篇回顧:上篇講了數據庫連接池的問題,其實關於是否是活動連接還是有很大問題可以挖掘的。這個有空蟲子再和大家交流了

本篇談下線程池的相關問題,希望各位看官留個爪印,應用程序池和數據庫連接池可能大部分程序員不需要關心那個,不過線程池可所謂是重頭戲了。

先把蟲子的觀點放上: 個人表示排斥在項目中使用ThreadPool這個類,至於.net中關聯到ThreadPool的資源我們暫且不做討論。如果需要操作線程池可以使用第三方例如SmartThreadPool或者自己按照自己的項目需求開發一個。

線程池的相關概念我就不多說了,同樣這裏我只介紹下。線程池中容易被忽視的問題。

一. 相對池外線程,池內線程操作的性能極差!

 

 ManualResetEvent[] MR = new ManualResetEvent[10];
            for (int i = 0; i < 10; i++)
            {
                MR[i] = new ManualResetEvent(false);
            }
            int a, b;
            ThreadPool.GetMaxThreads(out a, out b);
            Console.WriteLine(string.Format("(輔助線程的最大數目{0}  I/O線程的最大數目{1})    初始狀態", a, b));
            ThreadPool.GetAvailableThreads(out a, out b);
            Console.WriteLine(string.Format("(可用輔助線程的最大數目{0}  可用I/O線程的最大數目{1})    初始狀態", a, b));
        
            Stopwatch sw = Stopwatch.StartNew();
            for (int i = 0; i < 10; i++)
            {
              
                new Thread((qq) =>
                {
                    Console.WriteLine("這是個線程池外的線程"+qq.ToString());
                    MR[(int)qq].Set();
                    Thread.Sleep(5000);

                }) { }.Start(i);
            }
            WaitHandle.WaitAll(MR);
            Console.WriteLine("生成池外10個線程 共耗時" + sw.ElapsedMilliseconds);

            foreach (ManualResetEvent me in MR)
            {
                me.Reset();
            }
            Thread.Sleep(500);
            ThreadPool.GetAvailableThreads(out a, out b);
            Console.WriteLine(string.Format("(可用輔助線程的最大數目{0}  可用I/O線程的最大數目{1})    線程池外啓動線程後", a, b));

            sw = Stopwatch.StartNew();
            for (int i = 0; i < 10; i++)
            {
            ThreadPool.QueueUserWorkItem(qq =>
                {                  
                    Console.WriteLine("這是個線程池內的線程" + qq.ToString());
                    MR[(int)qq].Set();
                    Thread.Sleep(20000);
                    
                },i);
            }
            WaitHandle.WaitAll(MR);
            Console.WriteLine("生成池內10個線程 共耗時" + sw.ElapsedMilliseconds);

            Thread.Sleep(6000);
            ThreadPool.GetAvailableThreads(out a, out b);
            Console.WriteLine(string.Format("(可用輔助線程的最大數目{0}  可用I/O線程的最大數目{1})    線程池內啓動線程後", a, b));

在初始狀態後 生成線程的效率存在百倍的差距!!!不過線程池既然是池的作用那麼在程序運行中應該會好很多。

二。線程池內的線程只能是後臺線程。

三。不能爲線程設置優先級。在高精度的項目中線程池不適用。

四。所支持的Callback不能有返回值。WaitCallback只能帶一個object類型的參數,沒有任何返回值。

五。容易被幹擾,同時容易破壞項目的應用環境。舉些例子

static void Main(string[] args)
        {                    
            //哪些函數會影響線程池
            int a, b;
            Timer timer = new Timer((qq) =>
            {            
                Console.WriteLine("這是一個timer");
                Thread.Sleep(2000);

            }, null, 2000, 1000);
           
            ThreadPool.GetAvailableThreads(out a, out b);
            Console.WriteLine(string.Format("(可用輔助線程的最大數目{0}  可用I/O線程的最大數目{1})    Timer啓動後", a, b));
            timer.Dispose();

            timer = new Timer((qq) =>
            {          
                ThreadPool.GetAvailableThreads(out a, out b);
                Console.WriteLine(string.Format("(可用輔助線程的最大數目{0}/可用I/O線程的最大數目{1}) Timer資源佔用ing", a, b));
            }, null, 2000, 1000);

            var act = new Action(testmethod);
            var qqt = act.BeginInvoke(CallbackMethod, act);
       

            Console.ReadLine();
        }

        static void CallbackMethod(IAsyncResult ar)
        {
            var caller = (Action)ar.AsyncState;
            caller.EndInvoke(ar);
            Console.WriteLine("Action回調結束");
 
        }

        static void testmethod()
        {
            Console.WriteLine("Action開始");
            int a, b;
            ThreadPool.GetAvailableThreads(out a, out b);
            Console.WriteLine(string.Format("(可用輔助線程的最大數目{0}  可用I/O線程的最大數目{1})    Action啓動ing", a, b));
            Thread.Sleep(2000);
        
        }

至於還有哪些,大家可以各自討論,或者提出反對的意見。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章