<center><h1>.Net Async and Await</h1></center> ### 前言 當我們在撰寫程式時,時常會有需要大量處理資料或是運算的狀況, 這時候主執行緒會被占用,導致畫面被咬死或是直接停止渲染的狀況, 這時採用非同步的設計就可以很好的解決這項困難。 ### 同步與非同步 這兩個名詞很容易被搞混,尤其是對於新手工程師來說,這邊舉簡單的例子來說明, 假設今天有個畢業生要跑離校流程,需要等待紙本論文裝訂並到各處室簽署離校文件,最後將紙本論文以及文件一同繳交至圖書館: - 同步的狀況會是,這位畢業生會先去影印店請店員裝訂紙本論文,並會在影印店等待至裝訂完畢才至各處室簽屬文件,最後繳交至圖書館完成申請。 - 而非同步的狀況就比較不同,這會畢業生會去影印店請店員裝訂紙本論文,在裝訂的同時到各處室簽屬文件,等裝訂完畢後再回去拿,最後繳交文件及紙本論文至圖書館完成申請。  ### Async & Await 在 C# 中,非同步可以使用 async 與 await 這兩個關鍵字來達成。 async 可以被用來修飾方法,使用 async 修飾方法後,編譯器就會自動將其視為非同步, 使用 async 修飾方法後回傳值必須為 Task 物件,如需回傳其它物件,例如 int 或 string 等等,可使用 Task\<int\> 或 Task\<string\>。 ```csharp public async Task<string> GetResult() { Task.Delay(1000); return "Task"; } ``` 而 await 則是可用於呼叫 async 方法時使用,使用 await 修飾後,執行緒會等待直到執行完成。 完整範例如下: ```csharp! async Task printThesis() { Console.WriteLine("開始列印論文"); await Task.Delay(1000); Console.WriteLine("論文列印完成"); Console.WriteLine("開始裝訂論文"); await Task.Delay(1500); Console.WriteLine("論文裝訂完成"); } async Task signPaper() { Console.WriteLine("開始簽署文件"); await Task.Delay(300); Console.WriteLine("文件簽署完成"); } var thesis = printThesis(); var paper = signPaper(); await thesis; Console.WriteLine(); Console.WriteLine("取得論文"); await paper; Console.WriteLine("取得文件"); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("至圖書館交件"); Task.Delay(800).Wait(); Console.WriteLine("完成離校手續"); Console.ReadLine(); ``` 執行結果:  ### Task.WhenAll 我們可以利用 Task 提供的 WhenAll 來縮短程式碼,程式會於 WhenAll 內所有工作完成後回傳。 ```csharp async Task printThesis() { Console.WriteLine("開始列印論文"); await Task.Delay(1000); Console.WriteLine("論文列印完成"); Console.WriteLine("開始裝訂論文"); await Task.Delay(1500); Console.WriteLine("論文裝訂完成"); Console.WriteLine("取得論文"); Console.WriteLine(); } async Task signPaper() { Console.WriteLine("開始簽署文件"); await Task.Delay(300); Console.WriteLine("文件簽署完成"); Console.WriteLine("取得文件"); Console.WriteLine(); } await Task.WhenAll(new List<Task>() { printThesis(), signPaper() }); Console.WriteLine(); Console.WriteLine("至圖書館交件"); Task.Delay(800).Wait(); Console.WriteLine("完成離校手續"); Console.ReadLine(); ``` 執行結果:  ### Task.WhenAny WhenAny() 會於引數內任何 Task 完成時回傳,可以使用 Task.WhenAny() 來達到更好的等待效果: ```csharp! async Task printThesis() { Console.WriteLine("開始列印論文"); await Task.Delay(1000); Console.WriteLine("論文列印完成"); Console.WriteLine("開始裝訂論文"); await Task.Delay(1500); Console.WriteLine("論文裝訂完成"); } async Task signPaper() { Console.WriteLine("開始簽署文件"); await Task.Delay(300); Console.WriteLine("文件簽署完成"); } var thesis = printThesis(); var paper = signPaper(); var tasks = new List<Task>() { thesis, paper }; while (tasks.Count > 0) { Task finishedTask = await Task.WhenAny(tasks); if (finishedTask == thesis) { Console.WriteLine("取得論文"); Console.WriteLine(); } else if (finishedTask == paper) { Console.WriteLine("取得文件"); Console.WriteLine(); } tasks.Remove(finishedTask); } Console.WriteLine(); Console.WriteLine("至圖書館交件"); Task.Delay(800).Wait(); Console.WriteLine("完成離校手續"); Console.ReadLine(); ``` 執行結果:  ### Reference https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/ ###### tags: `C#` `.Net`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up