- 為什么要使用 Task
- Task 和 Thread 區別
- Task 介紹
- Task 簡單實現
- Task 執行狀態
為什么要使用 Task
線程是創建並發的底層工具,因此具有一定的局限性。
- 沒有簡單的方法可以從聯合(Join)線程得到“返回值”。因此必須創建一些共享域。當拋出一個異常時,捕捉和處理異常也是麻煩的。
- 線程完成之后,無法再次啟動該線程。相反,只能聯合(Join)它(在進程阻塞當前線程)。
任務是可組合的——使用延續將它們串聯在一起。它們可以使用線程池減少啟動延遲,而且它們可以通過TaskCompletionSource
使用回調方法,避免多個線程同時等待I/O密集操作。
Task 和 Thread 區別
1、任務是架構在線程之上的,也就是說任務最終還是要拋給線程去執行。
2、任務跟線程不是一對一的關系,比如開10個任務並不是說會開10個線程,這一點任務有點類似線程池,但是任務相比線程池有很小的開銷和精確的控制。
Task和Thread一樣,位於System.Threading命名空間下
與線程相比,Task
是一個更高級的抽象概念,它標識一個通過或不通過線程實現的並發操作。
Task 介紹
Task 類的表示單個操作不返回一個值,通常以異步方式執行。 Task 對象是一個的中心思想 基於任務的異步模式 首次引入.NET Framework 4 中。 因為由執行工作 Task 對象通常以異步方式執行在線程池線程上而不是以同步方式在主應用程序線程,您可以使用 Status 屬性,以及 IsCanceled, ,IsCompleted, ,和 IsFaulted 屬性,以確定任務的狀態。 大多數情況下,lambda 表達式用於指定的任務是執行的工作。
Task 簡單實現
通過使用Task的構造函數來創建任務,並調用Start方法來啟動任務並執行異步操作。
static void Main(string[] args) { Console.WriteLine("主線程執行業務處理."); //創建任務 Task task = new Task(() => { Console.WriteLine("使用System.Threading.Tasks.Task執行異步操作."); for (int i = 0; i < 10; i++) { Console.WriteLine(i); } }); //啟動任務,並安排到當前任務隊列線程中執行任務 task.Start(); Console.WriteLine("主線程執行其他處理"); }
從Framework 4.5開始,啟動一個由后台線程實現的Task,也可以使用靜態方法 Task.Run
Task task = Task.Run(() => { Thread.Sleep(2000); Console.WriteLine("Foo"); });
Task默認使用線程池,它們都是后台線程。意味當主線程結束時,所有任務都會隨之停止。
Task 執行狀態
1.等待(Wait)
調用Wait
方法,可以阻塞任務,直至任務完成,效果等同於Thread.Join
:
Task task = Task.Run(() => { Thread.Sleep(2000); Console.WriteLine("Foo"); }); Console.WriteLine(task.IsCompleted); //False task.Wait();//阻塞,直至任務完成 Console.WriteLine(task.IsCompleted); //True Console.ReadLine();
2. 返回值
Task<TResult>
允許任務返回一個值。調用Task.Run
,傳入一個Func<TResult>
代理(或者兼容的Lambda表達式),代替Action,就可以獲得一個Task<TResult>:
Task<int> task = Task.Run (() => { Console.WriteLine ("Foo"); return 3; }); int result = task.Result; // Blocks if not already finished Console.WriteLine (result); // 3
下面的例子創建一個任務,它使用LINQ就按前3百萬個整數(從2開始)中的素數個數:
Task<int> primeNumberTask = Task.Run(() => Enumerable.Range(2, 3000000).Count(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0))); Console.WriteLine("Task running..."); Console.WriteLine("The answer is " + primeNumberTask.Result);
這段代碼會打印“Task running...”,然后幾秒鍾后打印216815。
3. Task.Delay
Task.Delay
是Thread.Sleep
的異步版本
Task.Delay(5000).GetAwaiter().OnCompleted(()=>Console.WriteLine(42));
或者
Task.Delay(5000).ContinueWith(ant => Console.WriteLine(42));
參考資料:
https://www.jianshu.com/p/4444f2d77f3b
https://www.cnblogs.com/pengstone/archive/2012/12/23/2830238.html