線程池的技術背景
在物件導向編程中,建立和銷毀對象是很費時間的,因為建立一個對象要擷取記憶體資源或者其它更多資源,所以提高服務程式效率的一個手段就是儘可能減少建立和銷毀對象的次數,特別是一些很耗資源的對象建立和銷毀。如何利用已有對象來服務就是一個需要解決的關鍵問題,其實這就是一些"池化資源"技術產生的原因。比如大家所熟悉的資料庫連接池正是遵循這一思想而產生的,本文將介紹的線程池技術同樣符合這一思想。
線程池技術如何提高伺服器程式的效能
我所提到伺服器程式是指能夠接受客戶請求並能處理請求的程式,而不只是指那些接受網路客戶請求的網路伺服器程式。
多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。但如果對多線程應用不當,會增加對單個任務的處理時間。可以舉一個簡單的例子:
假設在一台伺服器完成一項任務的時間為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而在處理請求時浪費時間,從而提高效率。
這些都是假設,不能充分說明問題,下面我將討論區對話池的簡單實現並對該程式進行對比測試,以說明線程技術優點及應用領域。
線程池的簡單實現及對比測試
一般一個簡單線程池至少包含下列組成部分。
線程池管理器(ThreadPoolManager):用於建立並管理線程池
背景工作執行緒(WorkThread): 線程池中線程
任務介面(Task):每個任務必須實現的介面,以供背景工作執行緒調度任務的執行。
任務隊列:用於存放沒有處理的任務。提供一種緩衝機制。
接下來我示範了一個 最簡單的線程池。沒有進行任何最佳化的。
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<task> TaskQueue; private Queue<workthread> WorkThreadList; public ThreadPoolManager(int i) { TaskQueue = new Queue<task>(); WorkThreadList = new Queue<workthread>(); 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<workthread>(); 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; } } }}</workthread></workthread></task></workthread></task>
背景工作執行緒類
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<task> TaskQueue; private Task task; public WorkThread(ref Queue<task> 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></task>
task類和實作類別
using System;using System.Collections.Generic;using System.Linq;using System.Text; namespace ThreadManager{ public interface Task { /// <summary> /// set flag of task. /// </summary> void SetEnd(bool flag); /// <summary> /// start task. /// </summary> void StartTask(); /// <summary> /// end task. /// </summary> void EndTask(); /// <summary> /// get status of task. /// </summary> /// <returns></returns> 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都是在不斷的嘗試,使得效能降的很低,需要改進的方法是增加一個 訊號量的機制,不讓程式空轉!
在下一篇文章中我會進行最佳化,使得線程池真正的提高效率!
以上就是c#自己實現線程池功能(一)的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!