.net 中的async,await理解
理解:
1、async修飾的方法可理解為異步方法(必須要配合await,否則和普通方法無異)
2、當async方法執行遇到await,則立即將控制權轉移到async方法的調用者
3、由調用者決定是否需要等待async方法執行完再繼續往下執行
4、await會掛起當前方法,即阻塞當前方法繼續往下執行,轉交控制權給調用者
註意:如果調用一個async方 法,卻不使用await關鍵字來標記一個掛起點的話,程序將會忽略async關鍵字並以同步的方式執行。編譯器會對類似的問題發出警告。
例子一:(控制臺程序)
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 }
執行結果:
由返回結果可以知,此異步方法AsyncAction執行遇到await,即程序執行到此行立刻被掛起,將控制權限交給MyMain方法,由MyMain決定是否等待AsyncAction執行完再往下執行,此處由於執行AsyncAction方法前不加await,所以直接往下執行。而AsyncAction方法中的await Task.Run(包括)後的代碼會異步執行。
例子二:例子一中MyMain方法執行AsyncAction前面加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 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 }
執行結果:
由於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 }
執行結果:
.net 中的async,await理解