一:什么是異步
當一個方法被調用時立即返回,並獲取一個線程執行該方法內部的業務,調用者不用等待該方法執行完畢,我們稱這個方法為異步方法。
異步的好處在於非阻塞(調用線程不會暫停執行去等待子線程完成),因此我們把一些不需要立即使用結果、較耗時的任務設為異步執行,可以提高程序的運行效率。net4.0在ThreadPool的基礎上推出了Task類,微軟極力推薦使用Task來執行異步任務,現在C#類庫中的異步方法基本都用到了Task;net5.0推出了async/await,讓異步編程更為方便。本篇主要介紹Task、async/await相關的內容。
二:Task介紹
ThreadPool不能控制線程池中線程的執行順序,也不能獲取線程池內線程取消/異常/完成的通知。net4.0在ThreadPool的基礎上推出了Task,Task擁有線程池的優點,同時也解決了使用線程池不易控制的弊端。
1、Task創建與運行
1.1 創建task三種方式
Task task = new Task(() => { Console.WriteLine("第一個任務!"); }); task.Start(); Task.Factory.StartNew(() => { Console.WriteLine("第二個任務"); }); Task.Run(() => { Console.WriteLine("第三個任務"); }); Console.WriteLine("執行主線程!");
運行結果:

1.2 帶返回值的Task
var task = new Task<string>(() => { return "第一個任務"; }); task.Start(); var task2 = Task<string>.Factory.StartNew(() => { return "第二個任務"; }).Result; var task3 = Task<string>.Run<string>(() => { return "第三個任務"; }).Result; Console.WriteLine(task.Result); Console.WriteLine(task2); Console.WriteLine(task3); Console.WriteLine("執行主線程!"); Console.ReadKey();
運行結果:

1.3 Task同步執行
Task task = new Task(() => { Console.WriteLine("第一個任務!"); }); task.RunSynchronously();
2、Task的阻塞方法(Wait/WaitAll/WaitAny)
task.Wait()、task2.Wait()和Task.WaitAll(task,task2)意義相同
Task.WaitAny(task,task2)執行完任何一個即可執行下面代碼
Task task = new Task(() => { Console.WriteLine("第一個任務!"); }); task.Start(); Task task2 = new Task(() => { Console.WriteLine("第二個任務!"); }); task2.Start(); //task.Wait(); //task2.Wait(); Task.WaitAny(task,task2); //Task.WaitAll(task, task2);
3 Task的延續操作(WhenAny/WhenAll/ContinueWith)
WhenAll等待所有任務完成執行延續的操作
WhenAny等待某個任務完成執行延續的操作
ContinueWith延續執行
Task task = new Task(() => { Console.WriteLine("第一個任務!"); }); task.Start(); Task task2 = new Task(() => { Console.WriteLine("第二個任務!"); }); task2.Start(); Task.WhenAny(task, task2).ContinueWith((t) => { Console.WriteLine("延續后執行!"); }); //Task.WhenAll(task, task2).ContinueWith((t) => //{ // Console.WriteLine("延續后執行!"); //}); Console.WriteLine("執行主線程!"); Console.ReadKey();
3、Task的任務取消(CancellationTokenSource)
CancellationTokenSource source = new CancellationTokenSource(); //注冊任務取消的事件 source.Token.Register(() => { Console.WriteLine("任務被取消后執行!"); }); int index = 0; //開啟一個task執行任務 Task task1 = new Task(() => { while (!source.IsCancellationRequested) { Thread.Sleep(1000); Console.WriteLine($"第{++index}次執行,線程運行中..."); } }); task1.Start(); //延時取消,效果等同於Thread.Sleep(5000);source.Cancel(); source.CancelAfter(5000); Console.ReadKey();
三:異步方法
static void Main(string[] args) { var name = GetNameAsync().GetAwaiter().GetResult(); SaveInfoAsync().GetAwaiter().GetResult(); Console.WriteLine(name); } /// <summary> /// 異步帶返回值 /// </summary> /// <returns></returns> static async Task<string> GetNameAsync() { return "wuzhd"; } /// <summary> /// 異步無返回值 /// </summary> /// <returns></returns> static async Task SaveInfoAsync() { }
