程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> c#自己實現線程池功能(一)

c#自己實現線程池功能(一)

編輯:C#入門知識

c#自己實現線程池功能(一)


線程池的技術背景

在面向對象編程中,創建和銷毀對象是很費時間的,因為創建一個對象要獲取內存資源或者其它更多資源,所以提高服務程序效率的一個手段就是盡可能減少創建和銷毀對象的次數,特別是一些很耗資源的對象創建和銷毀。如何利用已有對象來服務就是一個需要解決的關鍵問題,其實這就是一些"池化資源"技術產生的原因。比如大家所熟悉的數據庫連接池正是遵循這一思想而產生的,本文將介紹的線程池技術同樣符合這一思想。

線程池技術如何提高服務器程序的性能

我所提到服務器程序是指能夠接受客戶請求並能處理請求的程序,而不只是指那些接受網絡客戶請求的網絡服務器程序。

多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閒置時間,增加處理器單元的吞吐能力。但如果對多線程應用不當,會增加對單個任務的處理時間。可以舉一個簡單的例子:

假設在一台服務器完成一項任務的時間為T

     T1 創建線程的時間
      T2 在線程中執行任務的時間,包括線程間同步所需時間
      T3 線程銷毀的時間

顯然T = T1+T2+T3。注意這是一個極度簡化的假設。

可以看出T1,T3是多線程本身的帶來的開銷,我們渴望減少T1,T3所用的時間,從而減少T的時間。但一些線程的使用者並沒有注意到這一點,所以在程序中頻繁的創建或銷毀線程,這導致T1和T3在T中占有相當比例。顯然這是突出了線程的弱點(T1,T3),而不是優點(並發性)。

線程池技術正是關注如何縮短或調整T1,T3時間的技術,從而提高服務器程序性能的。它把T1,T3分別安排在服務器程序的啟動和結束的時間段或者一些空閒的時間段,這樣在服務器程序處理客戶請求時,不會有T1,T3的開銷了。

線程池不僅調整T1,T3產生的時間段,而且它還顯著減少了創建線程的數目。在看一個例子:

假設一個服務器一天要處理50000個請求,並且每個請求需要一個單獨的線程完成。我們比較利用線程池技術和不利於線程池技術的服務器處理這些請求時所產生的線程總數。在線程池中,線程數一般是固定的,所以產生線程總數不會超過線程池中線程的數目或者上限(以下簡稱線程池尺寸),而如果服務器不利用線程池來處理這些請求則線程總數為50000。一般線程池尺寸是遠小於50000。所以利用線程池的服務器程序不會為了創建50000而在處理請求時浪費時間,從而提高效率。

這些都是假設,不能充分說明問題,下面我將討論線程池的簡單實現並對該程序進行對比測試,以說明線程技術優點及應用領域。

線程池的簡單實現及對比測試

一般一個簡單線程池至少包含下列組成部分。

  1. 線程池管理器(ThreadPoolManager):用於創建並管理線程池
  2. 工作線程(WorkThread): 線程池中線程
  3. 任務接口(Task):每個任務必須實現的接口,以供工作線程調度任務的執行。
  4. 任務隊列:用於存放沒有處理的任務。提供一種緩沖機制。
    接下來我演示了一個 最簡單的線程池。沒有進行任何優化的。
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    using System.Threading;
    
    namespace ThreadManager
    {
        public class ThreadPoolManager
        {
            private int MaxThreadNum;
            private int MinThreadNum;
            private int GrowStepNum;
            //線程數量
            public int ThreadNum{get;set;}
            //默認線程數量
            public int DefaultThreadNum { get; set; }
    
            private Queue TaskQueue;
            private Queue WorkThreadList;
    
            public ThreadPoolManager(int i)
            {
                TaskQueue = new Queue();
                WorkThreadList = new Queue();
                DefaultThreadNum = 10;
                if (i > 0)
                    DefaultThreadNum = i;
                CreateThreadPool(i);
            }
            public ThreadPoolManager():this(10)
            {
            }
            public bool IsAllTaskFinish()
            {
                return TaskQueue.Count == 0;
            }
            public void CreateThreadPool(int i)
            {
                if (WorkThreadList == null)
                    WorkThreadList = new Queue();
                lock (WorkThreadList)
                {
                    for (int j = 0; j < i;j++)
                    {
                        ThreadNum++;
                        WorkThread workthread = new WorkThread(ref TaskQueue,ThreadNum);
                        WorkThreadList.Enqueue(workthread);
                    }
                }
            }
            public void AddTask(Task task)
            {
               
                if (task == null)
                    return;
                lock (TaskQueue)
                {
                    TaskQueue.Enqueue(task);
                }
                //Monitor.Enter(TaskQueue);
                //TaskQueue.Enqueue(task);
                //Monitor.Exit(TaskQueue);
            }
            public void CloseThread()
            {
                //Object obj = null;
                while (WorkThreadList.Count != 0)
                {
                    try
                    {
                        WorkThread workthread = WorkThreadList.Dequeue();
                        workthread.CloseThread();
                        continue;
                    }
                    catch (Exception)
                    {
                    }
                    break;
                }
            }
        }
    }
    
    工作線程類
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    
    namespace ThreadManager
    {
        public class WorkThread
        {
            public int ThreadNum { get; set; }
            private bool flag;
            private Queue TaskQueue;
            private Task task;
            public WorkThread(ref Queue queue, int i)
            {
                this.TaskQueue = queue;
                ThreadNum = i;
                flag = true;
                new Thread(run).Start();
            }
            public void run()
            {
                while (flag && TaskQueue != null)
                {
                    //獲取任務
                    lock (TaskQueue)
                    {
                        try
                        {
                                task = TaskQueue.Dequeue();
                        }
                        catch (Exception)
                        {
                            task = null;
                        }
                        if (task == null)
                            continue;
                    }
                    try
                    {
                        task.SetEnd(false);
                        task.StartTask();
                    }
                    catch (Exception)
                    {
                    }
                    try
                    {
                        if (!task.IsEnd())
                        {
                            task.SetEnd(false);
                            task.EndTask();
                        }
                    }
                    catch (Exception)
                    {
                    }
    
                }//end of while
            }
            public void CloseThread()
            {
                flag = false;
                try
                {
                    if (task != null)
                        task.EndTask();
                }
                catch (Exception)
                {   
                }
            }
        }
    }
    task類和實現類
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ThreadManager
    {
        public interface Task
        {
            /// 
            /// set flag of task.
            /// 
            void SetEnd(bool flag);
            /// 
            /// start task.
            /// 
            void StartTask();
            /// 
            /// end task.
            /// 
            void EndTask();
            /// 
            /// get status of task.
            /// 
            /// 
            bool IsEnd();
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    
    namespace ThreadManager
    {
        public class TestTask:Task
        {
            private bool is_end;
            public void SetEnd(bool flag)
            {
                is_end = flag;
            }
            public void StartTask()
            {
                Run();
            }
            public void EndTask()
            {
                is_end = true;
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":"+"結束!");
            }
            public bool IsEnd()
            {
                return is_end;
            }
            public void Run()
            {
                for (int i = 0; i < 1000; i++)
                {
                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":"+i);
                }
            }
    
        }
    }
    


    這個簡單的模型存在的問題是,很多時候獲取TASK都是在不斷的嘗試,使得性能降的很低,需要改進的方法是增加一個 信號量的機制,不讓程序空轉!

    在下一篇文章中我會進行優化,使得線程池真正的提高效率!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved