談?wù)剬?duì).NET中async/await的理解
一、什么是同步?什么是異步?
在.net中,async 和 await 是兩個(gè)關(guān)鍵字,async 關(guān)鍵字用于聲明一個(gè)方法是異步方法,該方法可以包含一個(gè)或多個(gè) await 表達(dá)式。await 關(guān)鍵字是用于在異步方法中等待一個(gè)任務(wù)(Task 或 Task<T>對(duì)象)的完成。在 async 方法中使用 await表達(dá)式時(shí),會(huì)暫停當(dāng)前方法的執(zhí)行,直到等待的任務(wù)完成。在這段時(shí)間內(nèi),主線程可以去執(zhí)行其它操作。
什么是同步:當(dāng)一個(gè)方法被調(diào)用時(shí),調(diào)用者需要等待該方法執(zhí)行完畢后才會(huì)繼續(xù)往下執(zhí)行,我們稱這種方法為同步方法。
什么是異步:當(dāng)一個(gè)方法被調(diào)用時(shí)立即返回,并獲取一個(gè)線程執(zhí)(Task)行該方法內(nèi)部的業(yè)務(wù)邏輯,而調(diào)用者不需要等待這個(gè)方法執(zhí)行完畢,我們稱這種方法為異步方法。
二、async/await是怎么提高性能的?
異步的好處在于非阻塞(調(diào)用線程不會(huì)暫停執(zhí)行去等待子線程完成),因此,我們可以把一些不需要立即使用結(jié)果、耗時(shí)的任務(wù)設(shè)為異步去執(zhí)行,可以提高程序的執(zhí)行效率。
比如,一個(gè)主線程需要執(zhí)行 5 個(gè)方法,假設(shè)每個(gè)方法的分別用時(shí)為 0.1s、0.2s、0.3s、0.4s、0.5s,如果在同步編程中,這個(gè)主線程的執(zhí)行用時(shí)大概為1.5秒。而如果把這5個(gè)方法寫(xiě)成異步的形式,那么這個(gè)主線程大概用時(shí)為0.5秒。
這是為什么呢?這是因?yàn)?,在同步方法中,主線程在調(diào)用方法時(shí),需要把這個(gè)方法執(zhí)行完成之后再繼續(xù)調(diào)用后續(xù)的方法,主線程執(zhí)行這5個(gè)方法就好比一根線穿5顆珠子一樣,一顆一顆來(lái),所以主線程執(zhí)行所用時(shí)間大概為1.5秒。而在異步方法中,主線程在調(diào)用異步方法時(shí),主線程不會(huì)立即去執(zhí)行異步方法的,而是在遇到異步方法中的 await語(yǔ)句后返回一個(gè)任務(wù)(Task),然后再繼續(xù)調(diào)用后續(xù)的方法,這些任務(wù)的執(zhí)行是由 task創(chuàng)建一個(gè)子線程去執(zhí)行的,主線程執(zhí)行這5個(gè)異步方法就好比5個(gè)人拿5根線同時(shí)穿5顆珠子,所用時(shí)間就是用時(shí)最多的那個(gè),所以主線程執(zhí)行時(shí)間大概為0.5秒。
問(wèn)題:怎么解決在調(diào)用異步函數(shù)時(shí),主線程繼續(xù)向下執(zhí)行后,主線程是怎么回收或管理這個(gè)異步方法的執(zhí)行結(jié)果的。
1、await等待執(zhí)行
public class Demo { public async Task DemoAsync() { await Task.Delay(1000); Console.WriteLine("1秒后執(zhí)行"); } } public Class Program { static async Task Main(string[] args) { Demo demo = new Demo(); // 使用 await 等待DemoAsync的執(zhí)行 await demo.DemoAsync(); Console.ReadKey(); } }
2、使用事件
internal class Program { static void Main(string[] args) { Demo demo = new Demo(); demo.OnEvent += (() => { Console.WriteLine("事件訂閱"); }); demo.DemoAsync(); Console.ReadKey(); } } public class Demo { public event Action OnEvent; public async Task DemoAsync() { Console.WriteLine("開(kāi)始執(zhí)行"); await Task.Delay(1000); Console.WriteLine("1秒后執(zhí)行"); OnEvent?.Invoke(); } }
3、回調(diào)函數(shù)
internal class Program { static void Main(string[] args) { Demo demo = new Demo(); demo.DemoAsync(() => { Console.WriteLine("回調(diào)函數(shù)"); }); Console.ReadKey(); } } public class Demo { public async Task DemoAsync(Action callback) { Console.WriteLine("開(kāi)始執(zhí)行"); await Task.Delay(1000); callback?.Invoke(); Console.WriteLine("1秒后執(zhí)行"); } }
4、使用異步方法但不等待結(jié)果
這種方法知識(shí)啟動(dòng)了異步操作而不需要結(jié)果,可以簡(jiǎn)單的調(diào)用異步方法而不使用 await。這種方式不會(huì)阻塞主線程,也不會(huì)處理異步操作的結(jié)果。
internal class Program { static void Main(string[] args) { Demo demo = new Demo(); demo.DemoAsync(); Console.ReadKey(); } } public class Demo { public async Task DemoAsync() { Console.WriteLine("開(kāi)始執(zhí)行"); await Task.Delay(1000); Console.WriteLine("1秒后執(zhí)行"); } }
5、將異步結(jié)果存儲(chǔ)在變量中
如果想要在某個(gè)時(shí)刻獲取到異步操作中的結(jié)果,可以將異步操作的結(jié)果存儲(chǔ)在變量中,然后再訪問(wèn)它。
internal class Program { static void Main(string[] args) { Demo demo = new Demo(); var demoResult = demo.DemoAsync(); // 使用 wait等待異步的完成 demoResult.Wait(); if (demoResult.IsCompleted) { Console.WriteLine("str執(zhí)行完成"); Console.WriteLine(demoResult.Result); } Console.ReadKey(); } } public class Demo { public async Task<string> DemoAsync() { Console.WriteLine("開(kāi)始執(zhí)行"); await Task.Delay(1000); Console.WriteLine("1秒后執(zhí)行"); return "異步返回結(jié)果"; } }
三、異步到底解決了什么?到底起到了什么樣的作用?
1、提高響應(yīng)性:使用 async 和 await 可以避免等待長(zhǎng)時(shí)間運(yùn)行的操作(如 IO 操作)阻塞主線程,從而提高應(yīng)用程序的響應(yīng)性。
2、簡(jiǎn)化異步操作:async 和 await 使得編寫(xiě)異步代碼更接近同步代碼的寫(xiě)法,這降低了異步編程的復(fù)雜性和出錯(cuò)的概率。
3、優(yōu)化資源使用:異步操作允許線程在等待任務(wù)完成時(shí)釋放,這樣可以為其它任務(wù)騰出資源,而不是處于空閑等待狀態(tài)。
四、在使用異步時(shí)的一些問(wèn)題的解決
1、異步的傳遞性問(wèn)題
異步方法的異步效果會(huì)在調(diào)用鏈上向上傳遞的,導(dǎo)致異步方法的調(diào)用鏈上的一些列方法也會(huì)被標(biāo)記為異步。這種情況通常發(fā)生在下面場(chǎng)景中:
調(diào)用異步方法:如果一個(gè)方法調(diào)用了一個(gè)異步方法,那么這個(gè)方法也需要標(biāo)記為 async,并使用 await 等待結(jié)果。返回類型的變化:異步方法通常以 Task 或 Task<T> 類型返回,這意味著調(diào)用這些異步方法的其他方法也需要更新其返回類型以匹配 Task 或 Task<T> 。
異步方法的傳遞性的避免:
1、不使用 await 調(diào)用異步函數(shù):如果在調(diào)用異步函數(shù)時(shí),不需要等待異步函數(shù)的返回結(jié)果,那么可以不適用 await關(guān)鍵字調(diào)用異步函數(shù)。
2、使用 Task.Run 來(lái)啟動(dòng)異步操作:Task.Run 方法可以用來(lái)啟動(dòng)一個(gè)新的異步操作,它會(huì)提供一個(gè)新的任務(wù)來(lái)異步函數(shù),從而避免了異步的傳遞性。
3、使用事件或回調(diào)來(lái)處理異步的結(jié)果:如果異步函數(shù)需要通知調(diào)用者操作已完成,可以使用事件或回調(diào)來(lái)代替直接的 await 調(diào)用。
4、將異步結(jié)果存放在變量中:如果需要等待異步操作的結(jié)果,但又不想立即等待它,可以將異步任務(wù)存儲(chǔ)在變量中,然后在需要訪問(wèn)時(shí)使用 wait 方法來(lái)等待異步的完成。
好記性不然爛筆頭,在學(xué)習(xí)的路上留下點(diǎn)痕跡。希望能給大家?guī)?lái)幫助,也期待你的點(diǎn)贊和討論。
到此這篇關(guān)于談?wù)剬?duì).NET中async/await的理解的文章就介紹到這了,更多相關(guān).net async await內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Visual?Studio?2022常見(jiàn)的報(bào)錯(cuò)以及處理方案圖文詳解
許多用戶在使用Visual Studio的過(guò)程中常會(huì)遇到各種問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于Visual?Studio?2022常見(jiàn)的報(bào)錯(cuò)以及處理方案的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04ASP.NET驗(yàn)證碼實(shí)現(xiàn)(附源碼)
這篇文章主要介紹了ASP.NET驗(yàn)證碼實(shí)現(xiàn)過(guò)程,并為大家分享了源碼下載,感興趣的小伙伴們可以參考一下2015-11-11記一次EFCore類型轉(zhuǎn)換錯(cuò)誤及解決方案
這篇文章主要介紹了記一次EFCore類型轉(zhuǎn)換錯(cuò)誤及解決方案,幫助大家更好的理解和學(xué)習(xí)使用asp.net core,感興趣的朋友可以了解下2021-03-03DataGrid同時(shí)具有分頁(yè)和排序功能及注意點(diǎn)
DataGrid同時(shí)具有分頁(yè)和排序功能及注意點(diǎn)...2006-09-09asp.net簡(jiǎn)單實(shí)現(xiàn)單點(diǎn)登錄(SSO)的方法
這篇文章主要介紹了asp.net簡(jiǎn)單實(shí)現(xiàn)單點(diǎn)登錄(SSO)的方法,結(jié)合簡(jiǎn)單實(shí)例形式較為詳細(xì)的分析了單點(diǎn)登錄的原理與asp.net的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-12-12Asp.net SignalR應(yīng)用并實(shí)現(xiàn)群聊功能
這篇文章主要為大家分享了Asp.net SignalR應(yīng)用并實(shí)現(xiàn)群聊功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04ASP.NET自帶對(duì)象JSON字符串與實(shí)體類的轉(zhuǎn)換
這篇文章主要介紹了ASP.NET自帶對(duì)象JSON字符串與實(shí)體類的轉(zhuǎn)換,感興趣的小伙伴們可以參考一下2016-07-07System.Web.Routing入門(mén)及進(jìn)階
System.Web.Routing已經(jīng)作為一個(gè)程序集包含在.net3.5sp1中發(fā)布了。雖然我們并沒(méi)有在3.5sp1中發(fā)現(xiàn)Asp.net Mvc的蹤跡,但是亦以感覺(jué)到它離我們不遠(yuǎn)了2011-12-12