ASP.NET 異步返回的Action (編輯中。。。)
阿新 • • 發佈:2018-06-28
err 接收 直接 ogr ret 返回 上層 不理解 wait
新學.net,最近用到了ABP框架,發現了如下代碼:
public override async Task<UserDto> Get(EntityDto<long> input) { var user = await base.Get(input); var userRoles = await _userManager.GetRolesAsync(user.Id); user.Roles = userRoles.Select(ur => ur).ToArray();return user; }
看到後,對async , Task , await 完全不理解,就查閱了相關資料。
簡單說一下我的理解,這3個關鍵字都是多線程機制的一部分,目的是讓處理用戶請求的線程盡快結束此次請求,結束後,就可以用這個線程繼續接收其他的請求。
而費時的異步操作,交給後臺線程處理(這裏的後臺線程,應該不能響應用戶請求)。這樣一來,就能讓服務器更快地響應請求。
Task對象中封裝著線程相關的對象,async 和 await 都是為Task服務。 想在函數中使用await,就必須聲明函數為async的。
關於await 和 async 的理解,我貼2段代碼,這2段代碼是在搜資料時,從網上找到的,我對其進行了改進,感謝原作者的付出!
第一段
using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp2 { class Program { static void Main(string[] args) { Console.WriteLine("Main start-----Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); Test();Console.WriteLine("-----Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("-----Main end:{0}", Thread.CurrentThread.ManagedThreadId); Console.ReadLine(); } static async Task Test() { Console.WriteLine("======Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); // 方法打上async關鍵字,就可以用await調用同樣打上async的方法 await GetName(); Console.WriteLine("Middle---------Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); await GetName2(); Console.WriteLine("##########Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); } static async Task GetName() { Console.WriteLine("*****Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); // Delay 方法來自於.net 4.5 // await Task.Delay(3000); // 返回值前面加 async 之後,方法裏面就可以用await了 await Task.Run(() => { Thread.Sleep(3000); Console.WriteLine("^^^^^^^^Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); }); Console.WriteLine("$$$$$$$Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); } static async Task GetName2() { Console.WriteLine("!!!!!Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); await Task.Run(() => { Thread.Sleep(3000); Console.WriteLine("++++++++Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); }); Console.WriteLine("~~~~~~Current Thread Id :{0}", Thread.CurrentThread.ManagedThreadId); } } }
輸出如下:
Main start-----Current Thread Id :1 ======Current Thread Id :1 *****Current Thread Id :1 -----Current Thread Id :1 -----Main end:1 ^^^^^^^^Current Thread Id :3 $$$$$$$Current Thread Id :3 Middle---------Current Thread Id :3 !!!!!Current Thread Id :3 ++++++++Current Thread Id :4 ~~~~~~Current Thread Id :4 ##########Current Thread Id :4
上面這段代碼,可以明顯地看 代碼運行的線程,await會對被它阻塞的代碼的運行線程產生影響!
第二段代碼:
using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Console.WriteLine("我是主線程,線程ID:{0}", Thread.CurrentThread.ManagedThreadId); TestAsync(); Console.WriteLine("-----------------TestAsync 返回--------------------------"); Console.ReadLine(); } //為了在函數體內使用await,必須寫async,表示這是個異步函數。 //而這裏使用 await 的作用,就是能讓 TestAsync 函數立即返回main函數,去執行main之後的邏輯,而不用等待 await 的task.在await的task執行完畢後,繼續執行當前task。 //對於一個async函數,可以使用await 去等待結果返回,也可以不使用,就像main函數這樣,實現真正的異步效果,直接運行到了函數結尾。 static async Task TestAsync() { Console.WriteLine("調用GetReturnResult()之前,線程ID:{0}。當前時間:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss")); //創建task,但沒有等待 var name = GetReturnResult(); Console.WriteLine("調用GetReturnResult()之後,線程ID:{0}。當前時間:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss")); //會阻塞上層調用的寫法 //Console.WriteLine("得到GetReturnResult()方法的結果:{0}。當前時間:{1}", name.Result, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss")); //不會阻塞上層調用的寫法 //這個await 找到最終的那個 新線程await,並 跳過等待結果,直接返回 Console.WriteLine("得到GetReturnResult()方法的結果:{0}。當前時間:{1}", await name, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss")); Console.WriteLine("await 後面的邏輯 => TestAsync 最後一句"); } static Task<string> GetReturnResult() { Console.WriteLine("執行Task.Run之前, 線程ID:{0}", Thread.CurrentThread.ManagedThreadId); return Task.Run(() => { Console.WriteLine("並行線程:GetReturnResult()方法裏面線程ID: {0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("並行線程:running...."); Thread.Sleep(3000); return "我是返回值"; }); } } }
結果如下:
我是主線程,線程ID:1 調用GetReturnResult()之前,線程ID:1。當前時間:2018-06-28 03:06:32 執行Task.Run之前, 線程ID:1 調用GetReturnResult()之後,線程ID:1。當前時間:2018-06-28 03:06:32 -----------------TestAsync 返回-------------------------- 並行線程:GetReturnResult()方法裏面線程ID: 3 並行線程:running.... 得到GetReturnResult()方法的結果:我是返回值。當前時間:2018-06-28 03:06:35 await 後面的邏輯 => TestAsync 最後一句
上面這段代碼,可以看出async 和await 的具體效果: 主函數直接調用一個用async聲明的函數(不在前面加await),運行到async聲明的函數中的await後立即返回主函數,不會阻塞主函數的代碼塊。這個函數返回的task,一般都會和一個正在後臺線程相關。
ASP.NET 異步返回的Action (編輯中。。。)