async/await 是我們?cè)?ASP.NET 應(yīng)用程序中,寫(xiě)異步代碼最常用的兩個(gè)關(guān)鍵字,使用它倆,我們不需要考慮太多背后的東西,比如異步的原理等等,如果你的 ASP.NET 應(yīng)用程序是異步到底的,包含數(shù)據(jù)庫(kù)訪問(wèn)異步、網(wǎng)絡(luò)訪問(wèn)異步、服務(wù)調(diào)用異步等等,那么恭喜你,你的應(yīng)用程序是沒(méi)問(wèn)題的,但有一種情況是,你的應(yīng)用程序代碼比較老,是同步的,但現(xiàn)在你需要調(diào)用異步代碼,這該怎么辦呢?有人可能會(huì)說(shuō),很簡(jiǎn)單啊,不是有個(gè) .Result 嗎?但事實(shí)真的就這么簡(jiǎn)單嗎?我們來(lái)探究下。
首先,放出幾篇經(jīng)典文章:
上面文章的內(nèi)容,我們后面會(huì)說(shuō)。光看不練假把式,所以,如果真正要體會(huì) sync over async,我們還需要自己動(dòng)手進(jìn)行測(cè)試:
先說(shuō)明一下,在測(cè)試代碼中,異步調(diào)用使用的是 HttpClient.GetAsync 方法,并且測(cè)試請(qǐng)求執(zhí)行兩次,關(guān)于具體的分析,后面再進(jìn)行說(shuō)明。
測(cè)試代碼:
[Route("")][HttpGet]public string Index(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId1:" + Thread.CurrentThread.ManagedThreadId); var result = Test(); System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId4:" + Thread.CurrentThread.ManagedThreadId); return result;}public static string Test(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId2:" + Thread.CurrentThread.ManagedThreadId); using (var client = new HttpClient()) { var response = client.GetAsync(url).Result; System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId3:" + Thread.CurrentThread.ManagedThreadId); return response.Content.ReadAsStringAsync().Result; }}
輸出結(jié)果:
Thread.CurrentThread.ManagedThreadId1:13Thread.CurrentThread.ManagedThreadId2:13Thread.CurrentThread.ManagedThreadId3:13Thread.CurrentThread.ManagedThreadId4:13Thread.CurrentThread.ManagedThreadId1:6Thread.CurrentThread.ManagedThreadId2:6Thread.CurrentThread.ManagedThreadId3:6Thread.CurrentThread.ManagedThreadId4:6
簡(jiǎn)單總結(jié):同步代碼中調(diào)用異步,上面的測(cè)試代碼應(yīng)該是我們最常寫(xiě)的,為什么沒(méi)有出現(xiàn)線程阻塞,頁(yè)面卡死的情況呢?而且代碼中調(diào)用了 GetAsync,為什么請(qǐng)求線程只有一個(gè)?后面再說(shuō),我們接著測(cè)試。
測(cè)試代碼:
[Route("")][HttpGet]public string Index(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId1:" + Thread.CurrentThread.ManagedThreadId); var result = Task.Run(() => Test2()).Result; System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId4:" + Thread.CurrentThread.ManagedThreadId); return result;}public static async Task<string> Test2(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId2:" + Thread.CurrentThread.ManagedThreadId); using (var client = new HttpClient()) { var response = await client.GetAsync(url); System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId3:" + Thread.CurrentThread.ManagedThreadId); return await response.Content.ReadAsStringAsync(); }}
輸出結(jié)果:
Thread.CurrentThread.ManagedThreadId1:6Thread.CurrentThread.ManagedThreadId2:7Thread.CurrentThread.ManagedThreadId3:11Thread.CurrentThread.ManagedThreadId4:6Thread.CurrentThread.ManagedThreadId1:6Thread.CurrentThread.ManagedThreadId2:7Thread.CurrentThread.ManagedThreadId3:12Thread.CurrentThread.ManagedThreadId4:6
簡(jiǎn)單總結(jié):根據(jù)上面的輸出結(jié)果,我們發(fā)現(xiàn),在一個(gè)請(qǐng)求過(guò)程中,總共會(huì)出現(xiàn)三個(gè)線程,一個(gè)是開(kāi)始的請(qǐng)求線程,接著是 Task.Run 創(chuàng)建的一個(gè)線程,然后是異步方法中 await 等待的執(zhí)行線程,需要注意的是,ManagedThreadId1 和 ManagedThreadId4 始終是一樣的。
測(cè)試代碼:
[Route("")][HttpGet]public string Index(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId1:" + Thread.CurrentThread.ManagedThreadId); var result = Test3().Result; System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId4:" + Thread.CurrentThread.ManagedThreadId); return result;}public static async Task<string> Test3(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId2:" + Thread.CurrentThread.ManagedThreadId); using (var client = new HttpClient()) { var response = await client.GetAsync(url); System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId3:" + Thread.CurrentThread.ManagedThreadId); return await response.Content.ReadAsStringAsync(); }}
輸出結(jié)果:
Thread.CurrentThread.ManagedThreadId1:5Thread.CurrentThread.ManagedThreadId2:5
簡(jiǎn)單總結(jié):首先,頁(yè)面是卡死狀態(tài),ManagedThreadId3 并沒(méi)有輸出,也就是執(zhí)行到 await client.GetAsync
的時(shí)候,線程就阻塞了。
測(cè)試代碼:
[Route("")][HttpGet]public string Index(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId1:" + Thread.CurrentThread.ManagedThreadId); var result = Test4().Result; System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId4:" + Thread.CurrentThread.ManagedThreadId); return result;}public static async Task<string> Test4(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId2:" + Thread.CurrentThread.ManagedThreadId); return await Task.Run(() => { Thread.Sleep(1000); System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId3:" + Thread.CurrentThread.ManagedThreadId); return "xishuai"; });}
輸出結(jié)果:
Thread.CurrentThread.ManagedThreadId1:6Thread.CurrentThread.ManagedThreadId2:6Thread.CurrentThread.ManagedThreadId3:7
簡(jiǎn)單總結(jié):和第三種情況一樣,頁(yè)面也是卡死狀態(tài),但不同的是,ManagedThreadId3 是輸出的,測(cè)試它的主要目的是和第三種情況形成對(duì)比,以便了解 HttpClient.GetAsync
中到底是什么鬼?
測(cè)試代碼:
[Route("")][HttpGet]public string Index(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId1:" + Thread.CurrentThread.ManagedThreadId); var result = Test5().Result; System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId4:" + Thread.CurrentThread.ManagedThreadId); return result;}public static async Task<string> Test5(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId2:" + Thread.CurrentThread.ManagedThreadId); using (var client = new HttpClient()) { var task = client.GetAsync(url); var response = await task.ConfigureAwait(true); System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId3:" + Thread.CurrentThread.ManagedThreadId); return await response.Content.ReadAsStringAsync(); }}
輸出結(jié)果:
Thread.CurrentThread.ManagedThreadId1:6Thread.CurrentThread.ManagedThreadId2:6
簡(jiǎn)單總結(jié):和上面兩種情況一樣,頁(yè)面也是卡死狀態(tài),它的效果和第三種完全一樣,ManagedThreadId3 都沒(méi)有輸出的。
測(cè)試代碼:
[Route("")][HttpGet]public string Index(){ System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId1:" + Thread.CurrentThread.ManagedThreadId); var result = Test6().Result; System.Diagnostics.Debug.WriteLine("Thread.CurrentThread.ManagedThreadId4:" + Thread.CurrentThread.ManagedThreadId); return result;}publ
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注