C#中async和await的深入分析
大概理解
查瞭一個小時的資料:async和await
發現這個大神的解釋一針見血,深得我心!以最簡單的例子,解釋瞭async和await。妙~~~
大多情況下,分開才能體現async和await的價值!
但,await 並沒有這麼簡單。
深入分析
await和Wait()的區別
接下來繼續往下看:
await Task.Delay(3000); 和Task.Delay(3000).Wait(); 有沒有區別?
上代碼:
using System.Diagnostics; namespace await_async2 { internal class Program { static public void TestWait() { var t = Task.Factory.StartNew(() => { Console.WriteLine("Start"); Task.Delay(3000).Wait(); Console.WriteLine("Done"); }); t.Wait(); Console.WriteLine("All done"); } static public void TestWait2() { var t = Task.Factory.StartNew(async () => { Console.WriteLine("Start"); await Task.Delay(3000); Console.WriteLine("Done"); }); t.Wait(); Console.WriteLine("All done"); } static public void TestWait3() { var t = Task.Run(async () => { Console.WriteLine("Start"); await Task.Delay(3000); Console.WriteLine("Done"); }); t.Wait(); Console.WriteLine("All done"); } static void Main(string[] args) { TestWait2(); //避免程序提前退出,導致一些現象看不到 Task.Delay(5000).Wait(); } } }
首先,強調一下,最後一句 Task.Delay(5000).Wait(); 是必須的,不然,程序提前退出,導致一些現象看不到,從而蒙蔽瞭我們。
第1段代碼TestWait執行效果,如下:
第2段代碼TestWait2執行效果,如下:
第3段代碼TestWait3執行效果,如下:
現在給出結論:
Task.Delay(3000).Wait(); 這個就是同步等。
await Task.Delay(3000); 因為沒有分開來寫(見第一張圖),所以基本和同步等沒有區別。
但是如果 await Task.Delay(3000); 是寫到:Task.Factory.StartNew裡面的
static public void TestWait2() { var t = Task.Factory.StartNew(async () => { Console.WriteLine("Start"); await Task.Delay(3000); Console.WriteLine("Done"); }); t.Wait(); Console.WriteLine("All done"); }
那這個效果不一樣瞭,他們執行的權限丟出去瞭有點像python裡的yeild,來看下程序的執行順序:
這裡就看出瞭:await Task.Delay(3000); 和Task.Delay(3000).Wait(); 的區別瞭。(但是這種情況如果在道Task.Run裡面就體現不出來!)
然後,我有簡單做瞭一個實驗:
這就更明瞭瞭, await Task.Delay(3000); 就像設置瞭一個回調,一旦三秒時間一到,程序的指針就會回到await Task.Delay(3000);後面的位置,直到函數執行結束。再回到之前的位置。這就是所謂的用同步的方式寫異步的代碼吧。
但是,為啥在Task.Factory.StartNew才會體現出來,這個我就不清楚瞭,請各位大佬指點一下。
去掉Task.Run的Wait
再來對比一下,下面這兩個函數:
static public void TestWait8() { var t = Task.Run(async () => { Console.WriteLine("Start"); await Task.Delay(3000); Console.WriteLine("Done"); }); Console.WriteLine("All done"); } static public void TestWait8_5() { var t = Task.Factory.StartNew(async () => { Console.WriteLine("Start"); await Task.Delay(3000); Console.WriteLine("Done"); }); t.Wait(); Console.WriteLine("All done"); }
先看第一個TestWait8,由於Task.Run不再調用 t.Wait(),Task.Run內部這個線程和主線程是並行的關系。程序指針會在兩個線程中來回切換。如果一方中寫瞭await xxx,那程序指針必然跳到另一個線程。直達await結束才可能返回。 這種情形是比較多的。此時await能節省大量等待時間(比如IO操作時間),充分利用等待時間。
此時 Console.WriteLine("All done");會最先被打印出來。
再看第二個TestWait8_5(其實就是回顧一下),當程序執行到t.Wait()時,程序不會繼續向下瞭,(此時因為有t.Wait()的存在,所以子線程其實是優先於主線程的)而是進入到子線程的內部進程,試圖將這個線程執行完,但是再線程裡面遇到又遇到await Task.Delay(3000);此時程序指針不會再這裡死等,程序指針又跳回主線程繼續執行,直到三秒到瞭之後就會回到子線程,子線程執行完瞭之後,再回到主線程。
但是如果吧TestWait8_5 中 Task.Factory.StartNew 換成 Task.Run ,那麼前面的過程一樣,隻是執行到await Task.Delay(3000);時候,此時會死等,不會跳到主線程,而是一定等到這個子線程完結,再回主線程。
小結
總結一下就是,遇到await 一定會等,至於程序指針是先跳到其他線程,還是在此線程死等,就看你的線程函數這麼寫的瞭。
其他
.Await();
最後,還有個:Task.Delay(3000).Await();
這個是prsim對Task寫的的一個拓展方法(避免在主線程調用時,阻塞UI):
總結
到此這篇關於C#中async和await的文章就介紹到這瞭,更多相關C# async和await內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- C#中的Task.Delay()和Thread.Sleep()區別(代碼案例)
- c# Task.Wait()與awaiat Task異常處理的區別說明
- C#使用Task實現異步方法
- C#代碼延時的幾種實現
- 一篇文章弄懂C#中的async和await