理解:異步
一、async修飾的方法可理解爲異步方法(必需要配合await,不然和普通方法無異)
二、當async方法執行遇到await,則當即將控制權轉移到async方法的調用者
三、由調用者決定是否須要等待async方法執行完再繼續往下執行
四、await會掛起當前方法,即阻塞當前方法繼續往下執行,轉交控制權給調用者async
注意:若是調用一個async方 法,卻不使用await關鍵字來標記一個掛起點的話,程序將會忽略async關鍵字並以同步的方式執行。編譯器會對相似的問題發出警告。spa
例子一:(控制檯程序)線程
1 static void Main(string[] args) 2 { 3 MyMain();//因爲main方法沒法定義成async,顧此定義一個方法MyMain來表示main方法。 4 Console.Read(); 5 } 6 static async void MyMain() 7 { 8 Console.WriteLine("main方法開始執行"); 9 AsyncAction(); 10 Console.WriteLine("main方法繼續執行"); 11 Console.WriteLine("main方法執行結束"); 12 } 13 14 static async Task<string> AsyncAction() 15 { 16 Console.WriteLine("AsyncAction方法await以前"); 17 string result = await Task<string>.Run(() => 18 { 19 Thread.Sleep(1000); 20 Console.WriteLine("AsyncAction方法sleep一秒後"); 21 return "AsyncAction的返回值"; 22 }); 23 Console.WriteLine("AsyncAction方法await以後-{0}", result); 24 return result; 25 }
執行結果:3d
由返回結果能夠知,此異步方法AsyncAction執行遇到await,即程序執行到此行馬上被掛起,將控制權限交給MyMain方法,由MyMain決定是否等待AsyncAction執行完再往下執行,此處因爲執行AsyncAction方法前不加await,因此直接往下執行。而AsyncAction方法中的await Task.Run(包括)後的代碼會異步執行。日誌
例子二:例子一中MyMain方法執行AsyncAction前面加awaitcode
1 static void Main(string[] args) 2 { 3 MyMain();//因爲main方法沒法定義成async,顧此定義一個方法MyMain來表示main方法。 4 Console.Read(); 5 } 6 static async void MyMain() 7 { 8 Console.WriteLine("main方法開始執行"); 9 await AsyncAction(); 10 Console.WriteLine("main方法繼續執行"); 11 Console.WriteLine("main方法執行結束"); 12 } 13 14 static async Task<string> AsyncAction() 15 { 16 Console.WriteLine("AsyncAction方法await以前"); 17 string result = await Task<string>.Run(() => 18 { 19 Thread.Sleep(1000); 20 Console.WriteLine("AsyncAction方法sleep一秒後"); 21 return "AsyncAction的返回值"; 22 }); 23 Console.WriteLine("AsyncAction方法await以後-{0}", result); 24 return result; 25 }
執行結果:blog
因爲AsyncAction方法執行前加了await,故MyMain方法要等待其執行結束才繼續往下執行。編譯器
使用場景及用法分析:同步
當有某一操做執行時間較長或者執行結果對總體程序執行影響不大(通常此操做都會是一個獨立一個方法。)主線程的執行不依賴於此操做的執行結果。
常見於一些IO操做,如日誌的記錄,當觸發記錄日誌動做的時候,應該讓其獨立一個線程去執行,此時無論日誌記錄成功與否,
都不該該阻塞主線程的執行。
在上面的例子一中,能夠將AsyncAction方法中的 Task.Run 當成記錄日誌的動做,當程序執行到 await Task.Run後,
AsyncAction方法馬上被掛起,主線程MyMain繼續往下執行。
這裏可能有人會疑問?爲什麼不直接在主線程MyMain中直接開啓線程 Task.Run 來記錄日誌?
而是要定義到一個異步方法(此例子爲AsyncAction方法)中處理日誌。
是,若是此時只是爲了記錄日誌,也不是必需要寫到一個方法中。可是,
首先,這種單一功能的操做,本應該就是獨立寫到一個方法中。
其次是 AsyncAction方法 中的 await Task.Run 的返回值也許還有其餘操做。
以下面例子:記錄日誌以前,須要獲取登錄用戶的一些信息,而且將用戶信息一同保存到日誌中,若是寫到主線程MyMain中,則避免不了阻塞主線程(由於須要等待獲取用戶信息)。
固然,你也能夠將這兩個方法一塊兒寫到一個方法中由Task調用,這裏只是舉個例子來講明Async和await的用法場景。
1 static void Main(string[] args) 2 { 3 MyMain();//因爲main方法沒法定義成async,顧此定義一個方法MyMain來表示main方法。 4 Console.Read(); 5 } 6 static async void MyMain() 7 { 8 Console.WriteLine("main方法開始執行"); 9 WriteUserLog(); 10 Console.WriteLine("main方法繼續執行"); 11 Console.WriteLine("main方法執行結束"); 12 } 13 14 static async void WriteUserLog() 15 { 16 Console.WriteLine("獲取用戶信息以前"); 17 string userInfo = await GetUserInfoAsync(); //儘可能早的使用await,以便此方法儘快掛起(異步執行) 18 Console.WriteLine("寫入日誌以前"); 19 WriteLog(userInfo); 20 } 21 22 static Task<string> GetUserInfoAsync() 23 { 24 return Task.Factory.StartNew(() => { 25 Thread.Sleep(1000); 26 Console.WriteLine("獲取用戶信息完成"); 27 return "jxf"; 28 }); 29 } 30 31 static void WriteLog(string userInfo) 32 { 33 Thread.Sleep(1000); 34 Console.WriteLine("寫入日誌完成,用戶信息:{0}", userInfo); 35 }
執行結果: