線程池和任務
線程池
創建線程和銷毀線程是一個昂貴的操作,要耗費大量的時間。由於操作系統必須調度可運行的線程並執行上線文切換,所以太多的線程還對性能不利。
為了改善這個情況,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); //模擬其他工作
}
輸出:
任務
很容易使用ThreadPool的QueueUserWorkItem方法發起一次非同步的計算限制操作。但這個技術有許多限制。最大的問題是沒有內置的機制 讓你知道操作在什麼時候完成,也沒有機制在操作完成時得到返回值。為了克服這些限制(並解決其他一些問題),微軟引入了任務的概念。
通過using System.Threading.Tasks 命名空間中的類型來使用任務。
創建任務
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");
}
輸出
理解任務狀態和生命周期
task實例的執行取決於底層硬體和運行時可用的資源。因此,在您獲取了有關task實例的任何信息後,這個狀態可能會發生改變,因為task實例的狀態也在同時發生改變。當task到達它的3種可能的最終之一時,它再也回不去之前的任何狀態了,如圖所示。
T初始狀態:task實例有3種可能的初始狀態,詳細說明如圖
最終狀態:接下來,task實例可以轉換到running狀態,並且最終轉變到一個最終狀態。
如果task實例有關聯的子任務,那麼就不能認為這個task完成了,並且這個task將轉變到WaitingForChildrenToComplete 狀態。當task實例的子任務都完成後,這個Task將進入3種可能的最終狀態之一。詳細說明如下如圖
取消任務
如果想中斷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


※虛擬貨幣有多火?一文告訴你
※關於TRIM的優化技巧
※json和xml封裝數據、數據緩存到文件中
※MOD命名規範
※css中的層疊性及權重的比較
TAG:IT優就業 |
※線程池定製初探
※Python 並發編程之線程池/進程池
※如何設計一個實用的線程池?
※Python的Socket知識6:線程、線程鎖、線程池、上下文管理
※詳解 Tomcat 的連接數與線程池
※FutureTask 在線程池中應用和源碼解析
※你懂ThreadPoolExecutor線程池技術嗎?看源碼你會有全新的認識
※線程池ThreadPoolExecutor里Control state,ctl參數的分析(二)
※線程池ThreadPoolExecutor里Control state,ctl參數的分析(一)