當前位置:
首頁 > 知識 > 線程池和任務

線程池和任務

  1. 線程池

  • 創建線程和銷毀線程是一個昂貴的操作,要耗費大量的時間。由於操作系統必須調度可運行的線程並執行上線文切換,所以太多的線程還對性能不利。

    為了改善這個情況,clr包含了代碼來管理他自己的線程池。

    線程池是你的應用程序能使用的線程集合。

    線程池內部會維護一個 操作請求隊列。應用程序執行一個非同步請求操作時,將一個記錄項(entry)追加到線程池的隊列中。線程池的代碼從這個對立中

    提取記錄項,將這個記錄項派發(dispatch)給一個線程池線程。

    當線程池完成任務後,線程不會被銷毀。相反,線程會回到線程池,在哪裡進入空閑狀態,等待相應另一個請求。由於線程不銷毀自身,所以不在再產生額外的性能損失;

線程池和任務

我們來演示以線程池的方式非同步的調用一個方法


public static void MainThreadPool()

{

Console.WriteLine("主線程非同步操作隊列");

ThreadPool.QueueUserWorkItem(ThreadProc);

Console.WriteLine("主線程做其他工作");

Thread.Sleep(1000);//模擬其他工作

Console.WriteLine("主線程運行結束");

Console.ReadLine();

}

///

/// 與委託WaitCallback 簽名相同的回掉方法

///

/// 如果使用的是QueueUserWorkItem(WaitCallback callBack),該參數默認為null

static void ThreadProc(Object stateInfo)

{

Console.WriteLine("線程池工作線程執行回掉");

Thread.Sleep(1000); //模擬其他工作

}

輸出:

線程池和任務

任務

  1. 很容易使用ThreadPool的QueueUserWorkItem方法發起一次非同步的計算限制操作。但這個技術有許多限制。最大的問題是沒有內置的機制 讓你知道操作在什麼時候完成,也沒有機制在操作完成時得到返回值。為了克服這些限制(並解決其他一些問題),微軟引入了任務的概念。

    通過using System.Threading.Tasks 命名空間中的類型來使用任務。

  2. 創建任務

public static void RunGetStartTask()

{

//創建方式之一 :通過task的構造函數

Task t1 = new Task(Task1);

//創建方式之二:通過task工廠調用StartNew 創建並並啟用

Task t2 = Task.Factory.StartNew(Task2);

Console.WriteLine("t1任務Start之前狀態:{0},t2任務狀態:{1}", t1.Status, t2.Status);

t1.Start();

Console.WriteLine("t1任務Start之後狀態:{0},t2任務狀態:{1}", t1.Status, t2.Status);

Task.WaitAll(t1, t2);

Console.WriteLine("主線程執行完畢");

Console.WriteLine("t1最終狀態:{0},t2最終狀態:{1}", t1.Status, t2.Status);

Console.ReadLine();

}

public static void Task1()

{

Thread.Sleep(1000);

Console.WriteLine("運行task1");

}

public static void Task2()

{

Thread.Sleep(2000);

Console.WriteLine("運行task2");

}

輸出

線程池和任務

  1. 理解任務狀態和生命周期

  • task實例的執行取決於底層硬體和運行時可用的資源。因此,在您獲取了有關task實例的任何信息後,這個狀態可能會發生改變,因為task實例的狀態也在同時發生改變。當task到達它的3種可能的最終之一時,它再也回不去之前的任何狀態了,如圖所示。

  • T初始狀態:task實例有3種可能的初始狀態,詳細說明如圖

線程池和任務

線程池和任務

  • 最終狀態:接下來,task實例可以轉換到running狀態,並且最終轉變到一個最終狀態。

    如果task實例有關聯的子任務,那麼就不能認為這個task完成了,並且這個task將轉變到WaitingForChildrenToComplete 狀態。當task實例的子任務都完成後,這個Task將進入3種可能的最終狀態之一。詳細說明如下如圖

  1. 取消任務

  • 如果想中斷task實例的執行,可以通過取消標記(Cancellation Token)

  • CancellationTokenSource 能夠初始化取消的請求,而CancellationToken能夠將這些請求傳遞給非同步的操作。

public static void RunGetStartTaskCancel()

{

var cts = new CancellationTokenSource();

var ct = cts.Token;

var sw = Stopwatch.StartNew();

var t1 = Task.Factory.StartNew(() => Task1Cancel(ct), ct);

var t2 = Task.Factory.StartNew(() => Task2Cancel(ct), ct);

//主線程模擬1秒

Thread.Sleep(1000);

cts.Cancel();

try

{

if (!Task.WaitAll(new Task[] { t1, t2 }, 3000))

{

Console.WriteLine("Task1Cancel 和 Task2Cancel 超過了2秒完成.");

Console.WriteLine("t1狀態" + t1.Status.ToString());

Console.WriteLine("t2狀態" + t2.Status.ToString());

Console.ReadLine();

}

Console.ReadLine();

}

catch (AggregateException ex)

{

foreach (Exception innerException in ex.InnerExceptions)

{

Debug.WriteLine(innerException.ToString());

Console.WriteLine("異常消息:" + innerException.ToString());

}

if (t1.IsCanceled)

{

Console.WriteLine("t1 task 運行Task1Cancel 已取消");

}

if (t1.IsCanceled)

{

Console.WriteLine("t2 task 運行Task2Cancel 已取消");

}

Console.WriteLine("耗時" + sw.Elapsed.ToString());

Console.WriteLine("完成");

Console.ReadLine();

}

}

public static void Task1Cancel(CancellationToken ct)

{

ct.ThrowIfCancellationRequested();

var sw = Stopwatch.StartNew();

Thread.Sleep(1000);

Console.WriteLine("運行task1");

Console.WriteLine("task1:" + sw.Elapsed.ToString());

ct.ThrowIfCancellationRequested();

}

public static void Task2Cancel(CancellationToken ct)

{

ct.ThrowIfCancellationRequested();

var sw = Stopwatch.StartNew();

Thread.Sleep(2000);

Console.WriteLine("運行task2");

Console.WriteLine("task2:" + sw.Elapsed.ToString());

}

從任務獲取返回值

  • 目前,我們的任務實例還沒有返回值,他們都是運行一些不返回值的委託。正如開頭將的,任務是可以有返回值的。通過使用Task實例,其中TResult要替換為返回類型。

public static void RunGetStartTaskResult()

{

var t1 = Task.Factory.StartNew(() => GetTask1("ChengTian"));

//等待t1 完成

t1.Wait();

var t2 = Task.Factory.StartNew(() =>

{

for (int i = 0; i < t1.Result.Count; i++)

{

Console.WriteLine(t1.Result[i]);

}

});

Console.WriteLine("結束");

Console.ReadLine();

}

public static List GetTask1(string ss)

{

Thread.Sleep(1000);

return ss.ToList();

}

輸出返回值

線程池和任務

通過延續串聯任務

  • 改造下上面的例子,在t1任務完成之後啟動t2任務

public static void RunGetStartTaskContinueWith()

{

var t1 = Task.Factory.StartNew(() => GetTask1("ChengTian"));

var t2 = t1.ContinueWith(t =>

{

for (int i = 0; i < t1.Result.Count; i++)

{

Console.WriteLine(t1.Result[i]);

}

});

Console.WriteLine("結束");

Console.ReadLine();

}

可以在任何任務實例上調用ContinueWith方法,創建一個延續。 你也可以串聯很多任務,然後等待最後一個任務(在這個實例中為t2)執行完成.

(本文轉載自博客園)



50天安卓課,自己解決住宿問題即可免費學習!

http://www.ujiuye.com/xydt/2017/13748.html?wt.bd=qzb36000j

想就業就就業,優就業就業扶持計劃,拿到滿意的工作offer就是這麼簡單

http://www.ujiuye.com/zt/jyfc/?wt.bd=qzb36000j

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT優就業 的精彩文章:

虛擬貨幣有多火?一文告訴你
關於TRIM的優化技巧
json和xml封裝數據、數據緩存到文件中
MOD命名規範
css中的層疊性及權重的比較

TAG:IT優就業 |

您可能感興趣

線程池定製初探
Python 並發編程之線程池/進程池
如何設計一個實用的線程池?
Python的Socket知識6:線程、線程鎖、線程池、上下文管理
詳解 Tomcat 的連接數與線程池
FutureTask 在線程池中應用和源碼解析
你懂ThreadPoolExecutor線程池技術嗎?看源碼你會有全新的認識
線程池ThreadPoolExecutor里Control state,ctl參數的分析(二)
線程池ThreadPoolExecutor里Control state,ctl參數的分析(一)