SmartThreadPool 使用實戰,參數釋義


SmartThreadPool Github地址:

https://github.com/amibar/SmartThreadPool

首先是實例化的時候的參數的解釋

//Initialize SmartThreadPool & Make logs
//SmartThreadPool m_hThreadPool;
//m_hThreadPool = new SmartThreadPool();//聲明一個線程池
STPStartInfo stp = new STPStartInfo();//線程詳細配置參數
//m_hThreadPool.STPStartInfo這個屬性是只讀屬性,所以只能在實例化的時候設置
{
    stp.AsReadOnly();//返回一個只讀類型的STPStartInfo
    //一個枚舉值,儲存工作項執行完成后是否調用回調方法,
    //Never不調用,
    //WhenWorkItemCanceled只有當工作項目被取消時調用
    //WhenWorkItemNotCanceled只有當工作項目不取消調用
    //Always調用
    stp.CallToPostExecute = CallToPostExecute.Always;//在這里選擇總是回調
    //當工作項執行完成后,是否釋放工作項的參數,如果釋放,參數對象必須實現IDisposable接口
    stp.DisposeOfStateObjects = true;
    //當線程池中沒有工作項時,閑置的線程等待時間,超過這個時間后,會釋放掉這個閑置的線程,默認為60秒
    stp.IdleTimeout = 300;//300s
    //最大線程數,默認為25,
    //注意,由於windows的機制,所以一般最大線程最大設置成25,
    //如果設置成0的話,那么線程池將停止運行
    stp.MaxWorkerThreads = 15;//15 thread
    //只在STP執行Action<...>與Func<...>兩種任務時有效
    //在執行工作項的過程中,是否把參數傳遞到WorkItem中去,用做IWorkItemResult接口取State時使用,
    //如果設置為false那么IWorkItemResult.State是取不到值的
    //如果設置為true可以取到傳入參數的數組
    stp.FillStateWithArgs = true;
    //最小線程數,默認為0,當沒有工作項時,線程池最多剩余的線程數
    stp.MinWorkerThreads = 5;//5 thread
    //當工作項執行完畢后,默認的回調方法
    stp.PostExecuteWorkItemCallback = delegate(IWorkItemResult wir) { MessageBox.Show("ok" + wir.Result); };
    //是否需要等待start方法后再執行工作項,?默認為true,當true狀態時,STP必須執行Start方法,才會為線程分配工作項
    stp.StartSuspended = true;
}
m_hThreadPool = new SmartThreadPool(stp);//帶線程初始化的線程池初始化

以下是使用兩種方法定義函數運行等待返回結果的演示,一種是等待實例化中的對象全部執行完成,一種是等待其中的某些執行完成。

private void button1_Click(object sender, EventArgs e)
{
   
    //這個例子將演示傳入數個參數並且等待運行然后傳出的全過程
    SmartThreadPool stp = new SmartThreadPool();
    IWorkItemResult<string> resultCallback = stp.QueueWorkItem(new Amib.Threading.Func<string, string, string>(GetResultstring), "hello ", "world");
    stp.Start();
    stp.WaitForIdle();//等待該實例下的所有結果返回
    MessageBox.Show(resultCallback.Result);
    stp.Shutdown();
}

private string GetResultstring(string str, string str2)
{
    return str + str2;
}
private void button2_Click(object sender, EventArgs e)
{
    //這個例子將演示一批參數的傳入一批線程並且等待執行結束返回值
    SmartThreadPool stp = new SmartThreadPool();
    List<IWorkItemResult> t_lResultItem = new List<IWorkItemResult>();//不對IWorkItemResult定義其類型,其結果需要自己做類型轉換
    for (int step = 0; step != 100;step++ )
    {
        //這里使用另一種方法來做函數
        t_lResultItem.Add(stp.QueueWorkItem(new WorkItemCallback(GetObjectString), new string[] { "hello ", step.ToString() }));
    }
    stp.Start();
    //等待所需的結果返回
    if (SmartThreadPool.WaitAll(t_lResultItem.ToArray()))
    {
        foreach (IWorkItemResult t in t_lResultItem)
        {
            MakeLog(string.Format("{0}{1}", t.State, t.Result));
        }
    }
}

private object GetObjectString(object obj)
{
    return string.Format("{0}{1}", (obj as string[])[0], (obj as string[])[1]);
}
 

處理線程執行過程中出現的錯誤

 
private void button3_Click(object sender, EventArgs es)
{
    //處理線程執行過程中出現的錯誤
    SmartThreadPool stp = new SmartThreadPool();//如果需要將線程池設置為調用start的時候才運行,需要設置其StartSuspended參數為true,然后為其調用start方法來啟動
    IWorkItemResult<double> ret = stp.QueueWorkItem(new Amib.Threading.Func<double, double, double>(Diverse), 10.0, 0);
    //接收錯誤的句柄
    stp.Start();
    Exception e = null;
    double resule = ret.GetResult(out e);//在取出結果的時候判斷是否有錯誤產生
    if (e != null)
    {
        //在這里進行錯誤處理,錯誤在InnerException中
        MessageBox.Show(e.InnerException.Message);
    }
    else
    {
        MessageBox.Show(resule.ToString());
    }
    stp.Shutdown();
}

private double Diverse(double x, double y)
{
    return x/y;
}
 

使用線程分組

 
private void button4_Click(object sender, EventArgs e)
{
    //這里演示了線程的分組
    SmartThreadPool stp = new SmartThreadPool();
    //創建一個分組並用這個分組管理
    IWorkItemsGroup mainGroup = stp.CreateWorkItemsGroup(1);//如果需要設置這個分組為調用start的時候才開始運行,需要傳入WIGStartInfo參數,將其參數中的StartSuspended設置為true然后調用分組的start方法
    //向分組中添加任務->當然可以有返回值
    mainGroup.QueueWorkItem(new WorkItemCallback(GetObjectString), 123);
    //分組等待所有任務完成
    mainGroup.WaitForIdle();
    //關閉
    stp.Shutdown();
}
 

以下是SmartThreadPool的部分解釋

 
SmartThreadPool smartThreadPool = new SmartThreadPool();

//獲取當前線程池中的工作線程數,與InUseThreads可能會有差別,因為InUseThreads不包含Idle狀態的線程
int threadNum = smartThreadPool.ActiveThreads;
//取消所有工作項,如果工作項在執行,那么等待工作項執行完
smartThreadPool.Cancel();
//如果不想等待工作項執行完,
smartThreadPool.Cancel(true);
//線程池的最大並發數,即MaxWorkerThreads,
//如果修改后的Concurrency小於MinWorkerThreads,那么MinWorkerThreads也會隨之改變
smartThreadPool.Concurrency = 25;
//創建一個工作組,最大並發為3,工作組在后面會詳細說明,
smartThreadPool.CreateWorkItemsGroup(3);
//卸載線程池
smartThreadPool.Dispose();
//反回所有未執行的工作項的參數對象
smartThreadPool.GetStates();
//獲取線程池中正在工作的線程數,與ActiveThreads會有差別,因為ActiveThreads可能包含Idle狀態的線程
int useThreadNum = smartThreadPool.InUseThreads;
//當線程池用沒有工作項時,反回true,否則,反回false
bool IsIdle = smartThreadPool.IsIdle;
//同時並行執行多個方法,並且阻塞到所有工作項都執行完,這里會有多少個工作項就會創造多少個線程,
smartThreadPool.Join(new Action[] { new Action(Test) });
//獲取或設置最大線程數,即MaxWorkerThreads,
smartThreadPool.MaxThreads = 25;
//最小線程數,當沒有工作項時,線程池最多剩余的線程數
smartThreadPool.MinThreads = 0;
//線程池的名稱,沒什么特殊的用處,
smartThreadPool.Name = "StartThreadPool";
//當線程池中沒有工作項(即閑置)時觸發的事件
smartThreadPool.OnIdle += new WorkItemsGroupIdleHandler(smartThreadPool_OnIdle);
//當線程池啟動一個線程時,觸發的事件
smartThreadPool.OnThreadInitialization += new ThreadInitializationHandler(smartThreadPool_OnThreadInitialization);
//當線程池釋放一個線程時,所觸發的事件
smartThreadPool.OnThreadTermination += new ThreadTerminationHandler(smartThreadPool_OnThreadTermination);
//與Join方法類似,並行執行多個帶參數的方法,這里會有多少個工作項就會創造多少個線程
smartThreadPool.Pipe<object>(new object(), new Action<object>[] { new Action<object>(Test) });
//卸載線程池
smartThreadPool.Shutdown();
//啟動線程池
smartThreadPool.Start();
//STPStartInfo對象的只讀實例
STPStartInfo stpStartInfo = smartThreadPool.STPStartInfo;
//等待所有的工作項執行完成(即IsIdle為true)
smartThreadPool.WaitForIdle();
//獲取還未執行的工作項數量
int wiNum = smartThreadPool.WaitingCallbacks;
//WorkItemGroup的啟動信息的只讀實力
WIGStartInfo wigStartInfo = smartThreadPool.WIGStartInfo;
 

****************

1、為什么需要使用線程池(Thread Pool)

  • 減少線程間上下文切換。線程執行一定的時間片后,系統會自動把cpu切換給另一個線程使用,這時還需要保存當 前的線程上下文狀態,並加載新線程的上下文狀態。當程序中有大量的線程時,每個線程分得的時間片會越來越少,可能會出現線程未處理多少操作,就需要切換到 另一線程,這樣頻繁的線程間上下文切換會花費大量的cpu時間。
  • 減少內存占用。系統每創建一條物理線程,需要大概花費1MB的內存空間,許多程序喜歡先創建多條物理線程,並 周期輪詢來處理各自的任務,這樣既消耗了線程上下文切換的時間,還浪費了內存。這些任務可能只需要一條線程就能滿足要求。假如某一任務需要執行較長的周 期,線程池還可以自動增加線程,並在空閑時,銷毀線程,釋放占用的內存。

2、為什么不使用.Net默認的線程池

  • .Net默認的線程池(ThreadPool)是一個靜態類,所以是沒辦法自己創建一個新的程序池的。默認的線程池與應用程序域 (AppDomain)掛鈎,一個AppDomain只有一個線程池。假如在線程池中執行了一個周期較長的任務,一直占用着其中一個線程,可能就會影響到 應用程序域中的其他程序的性能。例如,假如在Asp.Net的線程池中執行一個周期較長的任務,就會影響請求的並發處理能力(線程池默認有個最大線程 數)。 3、SmartThreadPool特性和優點

SmartThreadPool特性如下:

  • 池中的線程數量會根據負載自動增減
  • 任務異步執行后可以返回值
  • 處於任務隊列中未執行的任務可以取消
  • 回調函數可以等待多個任務都執行完成后再觸發
  • 任務可以有優先級(priority)
  • 任務可以分組
  • 支持泛型Action<T> 和 Func<T>
  • 有性能監測機制

4、使用示例 最簡單的使用方法:

1
2
3
4
5
6
7
8
// 創建一個線程池
SmartThreadPool smartThreadPool = new SmartThreadPool();
 
  // 執行任務
smartThreadPool.QueueWorkItem(() =>
{
      Console.WriteLine( "Hello World!" );
});

帶返回值的任務:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 創建一個線程池
SmartThreadPool smartThreadPool = new SmartThreadPool();
 
// 執行任務
var result = smartThreadPool.QueueWorkItem(() =>
{
     var sum = 0;
     for (var i = 0; i < 10; i++)
         sum += i;
 
     return sum;
});
 
// 輸出計算結果
Console.WriteLine(result.Result);

等待多個任務執行完成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 創建一個線程池
SmartThreadPool smartThreadPool = new SmartThreadPool();
 
// 執行任務
var result1 = smartThreadPool.QueueWorkItem(() =>
{
     //模擬計算較長時間
     Thread.Sleep(5000);
 
     return 3;
});
 
var result2 = smartThreadPool.QueueWorkItem(() =>
{
     //模擬計算較長時間
     Thread.Sleep(3000);
 
     return 5;
});
 
bool success = SmartThreadPool.WaitAll(
     new IWorkItemResult[] { result1, result2 });
 
if (success)
{
     // 輸出結果
     Console.WriteLine(result1.Result);
     Console.WriteLine(result2.Result);
}

5、結論 使用SmartThreadPool可以簡單就實現支持多線程的程序,由線程池來管理線程,可以減少死鎖的出現。SmartThreadPool還支持簡單的生產者-消費者模式,當不需要對任務進行持久化時,還是很好用的。

6、擴展閱讀 http://www.codeproject.com/KB/threads/smartthreadpool.aspx

http://smartthreadpool.codeplex.com/

http://www.albahari.com/threading/

 轉載於:https://www.cnblogs.com/zeroone/p/3283045.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM