Task 是什么 ?
Task 是一個類, 它表示一個操作不返回一個值,通常以異步方式執行。
Task 對象是一個的中心思想 基於任務的異步模式 首次引入.NET Framework 4 中。
System.Threading.Tasks.Task
System.Threading.Tasks.Task<TResult>
因為由執行工作 Task 對象通常以異步方式執行在線程池線程上而不是以同步方式在主應用程序線程,您可以使用 Status 屬性,以及 IsCanceled, ,IsCompleted, ,和 IsFaulted 屬性,以確定任務的狀態。 大多數情況下,lambda 表達式用於指定的任務是執行的工作。
Task 怎么用 ?
Task 可以多種方式創建實例。 最常用的方法,它位於開頭 .NET Framework 4.5, ,是調用靜態 Run 方法。 Run 方法提供了簡單的方法來啟動任務使用默認值,並且無需額外的參數。 下面的示例使用 Run(Action) 方法來啟動循環,然后顯示循環迭代數的任務︰
using System; using System.Threading.Tasks; public class Example { public static void Main() { Task t = Task.Run( () => { // Just loop. int ctr = 0; for (ctr = 0; ctr <= 1000000; ctr++) {} Console.WriteLine("Finished {0} loop iterations", ctr); } ); t.Wait(); } }
using System; using System.Threading.Tasks; public class Example { public static void Main() { Task t = Task.Factory.StartNew( () => { // Just loop. int ctr = 0; for (ctr = 0; ctr <= 1000000; ctr++) {} Console.WriteLine("Finished {0} loop iterations", ctr); } ); t.Wait(); } }
因為任務通常運行以異步方式在線程池線程上,創建並啟動任務的線程將繼續執行,一旦該任務已實例化。 在某些情況下,當調用線程的主應用程序線程,該應用程序可能會終止之前任何任務實際開始執行。 其他情況下,應用程序的邏輯可能需要調用線程繼續執行,僅當一個或多個任務執行完畢。 您可以同步調用線程的執行,以及異步任務它啟動通過調用 Wait 方法來等待要完成的一個或多個任務。
若要等待完成一項任務,可以調用其 Task.Wait 方法。 調用 Wait 方法將一直阻塞調用線程直到單一類實例都已完成執行。
下面的示例調用無參數 Wait() 方法,以無條件地等待,直到任務完成。 該任務通過調用來模擬工作 Thread.Sleep 方法進入睡眠狀態兩秒鍾。
using System; using System.Threading; using System.Threading.Tasks; class Program { static Random rand = new Random(); static void Main() { // Wait on a single task with no timeout specified. Task taskA = Task.Run( () => Thread.Sleep(2000)); Console.WriteLine("taskA Status: {0}", taskA.Status); try { taskA.Wait(); Console.WriteLine("taskA Status: {0}", taskA.Status); } catch (AggregateException) { Console.WriteLine("Exception in taskA."); } } }
您可以有條件地等待任務完成。 Wait(Int32) 和 Wait(TimeSpan) 方法阻止調用線程,直到任務完成或超時間隔結束,具體取決於第一個。 由於下面的示例將啟動一個任務,它在睡眠兩秒鍾,但定義的一秒的超時值,調用線程受到阻止,直到超時到期和之前的任務已完成執行。
using System; using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { // Wait on a single task with a timeout specified. Task taskA = Task.Run( () => Thread.Sleep(2000)); try { taskA.Wait(1000); // Wait for 1 second. bool completed = taskA.IsCompleted; Console.WriteLine("Task A completed: {0}, Status: {1}", completed, taskA.Status); if (! completed) Console.WriteLine("Timed out before task A completed."); } catch (AggregateException) { Console.WriteLine("Exception in taskA."); } } }
你也可以通過調用提供一個取消標記 Wait(CancellationToken) 和 Wait(Int32, CancellationToken) 方法。 如果該令牌的 IsCancellationRequested 屬性是 true, ,取消等待; 如果它變為 true 時 Wait 方法終止。
在某些情況下,您可能想要等待的執行的任務的一系列的第一個完成,但不是任務它的關注。 出於此目的,您可以調用的重載之一 Task.WaitAll 方法。 下面的示例創建三個任務,其中每個休眠的隨機數字生成器確定時間間隔。 WaitAny(Task[]) 方法等待第一個任務完成。 此示例隨后顯示所有三個任務的狀態的信息。
using System;
using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { var tasks = new Task[3]; var rnd = new Random(); for (int ctr = 0; ctr <= 2; ctr++) tasks[ctr] = Task.Run( () => Thread.Sleep(rnd.Next(500, 3000))); try {s int index = Task.WaitAny(tasks); Console.WriteLine("Task #{0} completed first.\n", tasks[index].Id); Console.WriteLine("Status of all tasks:"); foreach (var t in tasks) Console.WriteLine(" Task #{0}: {1}", t.Id, t.Status); } catch (AggregateException) { Console.WriteLine("An exception occurred."); } } }
您也可以等待所有任務的調用以完成一系列 WaitAll 方法。 下面的示例創建十個任務,等待所有十若要完成,然后顯示其狀態。
using System;
using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { // Wait for all tasks to complete. Task[] tasks = new Task[10]; for (int i = 0; i < 10; i++) { tasks[i] = Task.Run(() => Thread.Sleep(2000)); } try { Task.WaitAll(tasks); } catch (AggregateException ae) { Console.WriteLine("One or more exceptions occurred: "); foreach (var ex in ae.Flatten().InnerExceptions) Console.WriteLine(" {0}", ex.Message); } Console.WriteLine("Status of completed tasks:"); foreach (var t in tasks) Console.WriteLine(" Task #{0}: {1}", t.Id, t.Status); } }
請注意,等待一個或多個任務完成時,則在正在運行的任務引發的任何異常傳播調用的線程上 Wait 方法,如以下示例所示。 它將啟動其中三個正常完成的 12 任務和三個哪些引發的異常。 剩余的六項任務,三個早於開始日期,將被取消,而三個將被取消時執行它們。 引發異常 WaitAll 方法調用,並且是處理 try/catch 塊。
using System;
using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { // Create a cancellation token and cancel it. var source1 = new CancellationTokenSource(); var token1 = source1.Token; source1.Cancel(); // Create a cancellation token for later cancellation. var source2 = new CancellationTokenSource(); var token2 = source2.Token; // Create a series of tasks that will complete, be cancelled, // timeout, or throw an exception. Task[] tasks = new Task[12]; for (int i = 0; i < 12; i++) { switch (i % 4) { // Task should run to completion. case 0: tasks[i] = Task.Run(() => Thread.Sleep(2000)); break; // Task should be set to canceled state. case 1: tasks[i] = Task.Run( () => Thread.Sleep(2000), token1); break; case 2: // Task should throw an exception. tasks[i] = Task.Run( () => { throw new NotSupportedException(); } ); break; case 3: // Task should examine cancellation token. tasks[i] = Task.Run( () => { Thread.Sleep(2000); if (token2.IsCancellationRequested) token2.ThrowIfCancellationRequested(); Thread.Sleep(500); }, token2); break; } } Thread.Sleep(250); source2.Cancel(); try { Task.WaitAll(tasks); } catch (AggregateException ae) { Console.WriteLine("One or more exceptions occurred:"); foreach (var ex in ae.InnerExceptions) Console.WriteLine(" {0}: {1}", ex.GetType().Name, ex.Message); } Console.WriteLine("\nStatus of tasks:"); foreach (var t in tasks) { Console.WriteLine(" Task #{0}: {1}", t.Id, t.Status); if (t.Exception != null) { foreach (var ex in t.Exception.InnerExceptions) Console.WriteLine(" {0}: {1}", ex.GetType().Name, ex.Message); } } } }
四: 並行迭代 Task.Parallel
API 會判定同時執行多少個線程效率最高。效率由一個爬山算法來決定。
一個parallel並行的例子