一文搞懂c# await,async執(zhí)行流
昨天有朋友在公眾號(hào)發(fā)消息說(shuō)看不懂a(chǎn)wait,async執(zhí)行流,其實(shí)看不懂太正常了,因?yàn)槟銢](méi)經(jīng)過(guò)社會(huì)的毒打,沒(méi)吃過(guò)牢飯就不知道自由有多重要,沒(méi)生過(guò)病就不知道健康有多重要,沒(méi)用過(guò)ContinueWith就不知道await,async有多重要,下面我舉兩個(gè)案例佐證一下?
一:案例一 【嵌套下的異步】
寫了這么多年的程序,相信大家都知道連接數(shù)據(jù)庫(kù)少不了這幾個(gè)對(duì)象,DbConnection,DbCommand,DbDataReader等等。。先來(lái)看看ContinueWith在連接數(shù)據(jù)庫(kù)時(shí)嵌套過(guò)深的尷尬。
1. NetFramework 4.0之前的寫法
這個(gè)時(shí)期的代碼沒(méi)有什么好說(shuō)的,都是程式代碼,一擼到底,簡(jiǎn)潔明了。
public static int SyncGetCount() { using (var connection = new MySqlConnection("server=xxx.xxx.xxx.xxx;userid=xxx;password=xxx;database=xxx;charset=utf8;port=3306;")) { connection.Open(); using (var command = connection.CreateCommand()) { command.CommandText = "select count(1) from messages"; var count = command.ExecuteScalar(); Console.WriteLine($"記錄條數(shù):{count}"); return Convert.ToInt32(count); } } }
output
記錄條數(shù):75896
2. NetFramework 4.0下ContinueWith的寫法
當(dāng)年異步和并發(fā)編程概念特別火,火熱度參考現(xiàn)在的直播帶貨,這個(gè)時(shí)期的C#率先使用新的Task一網(wǎng)兜,在數(shù)據(jù)庫(kù)操作的幾大類中開(kāi)始有了Async結(jié)尾的方法,如OpenAsync,ExecuteScalarAsync,ReadAsync 等等,但遺憾的是那時(shí)寫異步,只能像下面這樣寫。
public static Task<object> ContinueWithGetCount() { var connection = new MySqlConnection("server=xxx.xxx.xxx.xxx;userid=xxx;password=xxx;database=xxx;charset=utf8;port=3306;"); var task = connection.OpenAsync().ContinueWith(t1 => { var command = connection.CreateCommand(); command.CommandText = "select count(1) from messages"; return command.ExecuteScalarAsync().ContinueWith(t2 => { command.Dispose(); connection.Dispose(); Console.WriteLine($"記錄條數(shù):{t2.Result}"); return t2.Result; }); }).Unwrap(); return task; }
output
記錄條數(shù):75896
相比同步代碼,這異步代碼寫的是不是很憋屈,為了應(yīng)對(duì)漸進(jìn)式的Async方法,我不得不進(jìn)行ContinueWith的深層嵌套,如果Async更多,那對(duì)可讀性將是毀滅性的打擊,這就是所謂的回調(diào)地獄。
3. NetFramework 4.5 下 await,async的寫法
寫到這里讓我想起了邢老大的那本自傳書《左手夢(mèng)想,右手療傷》,這苦這心酸只有真正經(jīng)歷過(guò)的人才會(huì)懂,沒(méi)有人能夠隨隨便便成功,接下來(lái)大家的期望就是如何做到有同步式的代碼又有異步功效,魚和熊掌我都要,當(dāng)然是可以的,看看如何用await,async進(jìn)行改造。
public static async Task<int> AsyncGetCount() { using (var connection = new MySqlConnection("server=xxx.xxx.xxx.xxx;userid=xxx;password=xxx;database=xxx;charset=utf8;port=3306;")) { await connection.OpenAsync(); using (var command = connection.CreateCommand()) { command.CommandText = "select count(1) from messages"; var count = await command.ExecuteScalarAsync(); Console.WriteLine($"記錄條數(shù):{count}"); return Convert.ToInt32(count); } } }
output
記錄條數(shù):75896
上面這代碼太簡(jiǎn)潔了,眼花的朋友還以為是同步代碼呢? 改造的地方也僅僅是方法簽名處加上一個(gè)async,異步方法前加上await,相當(dāng)于痛苦版的ContinueWith。
二:案例二 【循環(huán)下的異步】
上一個(gè)案例只是使用ExecuteScalarAsync從數(shù)據(jù)庫(kù)中讀取一個(gè)值來(lái)得到表中的記錄數(shù),在業(yè)務(wù)開(kāi)發(fā)中更多的是使用ExecuteReader從數(shù)據(jù)庫(kù)中獲取批量記錄,這個(gè)就涉及到了如何在循環(huán)中使用異步,想想就太苦難了(┬_┬)。
1. NetFramework 4.0之前的寫法
這里我從messages表中讀取5條記錄,然后輸出到控制臺(tái),詳細(xì)代碼如下:
public static List<string> SyncGetMessageList() { var messageList = new List<string>(); using (var connection = new MySqlConnection("server=xxx.xxx.xxx.xxx;userid=xxx;password=xxx;database=xxx;charset=utf8;port=3306;")) { connection.Open(); using (var command = connection.CreateCommand()) { command.CommandText = "select message from messages limit 5;"; using (var reader = command.ExecuteReader()) { while (reader.Read()) { messageList.Add(reader.GetString("message")); } } } } messageList.ForEach(Console.WriteLine); return messageList; }
output
你需要忘記失去的,感激擁有的,和期待將至的。
以前的找不到了。
對(duì)于編譯錯(cuò)誤,刪除Pods文件夾然后重新pod install已經(jīng)成為經(jīng)驗(yàn)。次。
Hello,Is there anyone here?
放松心情
2. NetFramework 4.0下ContinueWith的寫法
要想用ContinueWith完成這功能,最簡(jiǎn)單有效的辦法就是使用遞歸,用遞歸的方式把若干個(gè)ContinueWith串聯(lián)起來(lái),而要用遞歸的話還要單獨(dú)定義一個(gè)方法,寫的有點(diǎn)亂,大家將就著看吧。
public class Program { public static void Main(string[] args) { var task = ContinueWithAsyncGetMessageList(); task.Result.ForEach(Console.WriteLine); Console.Read(); } public static Task<List<string>> ContinueWithAsyncGetMessageList() { var connection = new MySqlConnection("server=xxx.xxx.xxx.xxx;userid=xxx;password=xxx;database=xxx;charset=utf8;port=3306;"); var task = connection.OpenAsync().ContinueWith(t1 => { var messageList = new List<string>(); var command = connection.CreateCommand(); command.CommandText = "select message from messages limit 5;"; return command.ExecuteReaderAsync().ContinueWith(t2 => { var reader = (MySqlDataReader)t2.Result; return GetMessageList(reader, messageList).ContinueWith(t3 => { reader.Dispose(); command.Dispose(); connection.Dispose(); }); }).Unwrap().ContinueWith(t3 => messageList); }).Unwrap(); return task; } /// <summary> /// 采用遞歸處理循環(huán) /// </summary> /// <param name="reader"></param> /// <param name="messageList"></param> /// <returns></returns> public static Task<List<string>> GetMessageList(MySqlDataReader reader, List<string> messageList) { var task = reader.ReadAsync().ContinueWith(t => { if (t.Result) { var massage = reader.GetString("message"); messageList.Add(massage); return GetMessageList(reader, messageList); } else { return Task.FromResult(new List<string>()); } }).Unwrap(); return task; } }
output
你需要忘記失去的,感激擁有的,和期待將至的。
以前的找不到了。
對(duì)于編譯錯(cuò)誤,刪除Pods文件夾然后重新pod install已經(jīng)成為經(jīng)驗(yàn)。次。
Hello,Is there anyone here?
放松心情
在遞歸下探的過(guò)程中把messageList集合給填滿了,而后將messageList返回給調(diào)用端即可,如果沒(méi)看明白,我畫一張圖吧!
在遞歸下探的過(guò)程中把messageList集合給填滿了,而后將messageList返回給調(diào)用端即可,如果沒(méi)看明白,我畫一張圖吧!
3. NetFramework 4.5 下 await,async的寫法
😄,剛剛是不是噩夢(mèng)般經(jīng)歷,救世主來(lái)啦,還是要魚和熊掌一起兼得
public static async Task<List<string>> AsyncGetMessageList() { var messageList = new List<string>(); using (var connection = new MySqlConnection("server=xxx.xxx.xxx.xxx;userid=xxx;password=xxx;database=xxx;charset=utf8;port=3306;")) { await connection.OpenAsync(); using (var command = connection.CreateCommand()) { command.CommandText = "select message from messages limit 5;"; using (var reader = await command.ExecuteReaderAsync()) { while (await reader.ReadAsync()) { messageList.Add(reader["message"].ToString()); } } } } return messageList; }
output
你需要忘記失去的,感激擁有的,和期待將至的。
以前的找不到了。
對(duì)于編譯錯(cuò)誤,刪除Pods文件夾然后重新pod install已經(jīng)成為經(jīng)驗(yàn)。次。
Hello,Is there anyone here?
放松心情
天底下還有如此簡(jiǎn)潔的代碼就可以實(shí)現(xiàn)ContinueWith那種垃圾般代碼所實(shí)現(xiàn)的功能,我都想仰天長(zhǎng)嘯,我太難了。
三:總結(jié)
還是那句話,你沒(méi)有被傷過(guò),永遠(yuǎn)不會(huì)體會(huì)到那種刻骨銘心的痛。
以上就是一文搞懂c# await,async執(zhí)行流的詳細(xì)內(nèi)容,更多關(guān)于c# await,async執(zhí)行流的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何用C#實(shí)現(xiàn)SAGA分布式事務(wù)
大家好,本篇文章主要講的是如何用C#實(shí)現(xiàn)SAGA分布式事務(wù),感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01c#多線程網(wǎng)絡(luò)聊天程序代碼分享(服務(wù)器端和客戶端)
本程序使用VS2005 制作,程序分為三塊,XuLIeHua類庫(kù)下有我寫的把結(jié)構(gòu)序列化的類,還有就是服務(wù)器端和客戶端2013-12-12C#中使用HttpDownLoadHelper下載文件實(shí)例
這篇文章主要介紹了C#中使用HttpDownLoadHelper下載文件的方法,并實(shí)例講述了在webfrom中與在mvc中的實(shí)現(xiàn)方法,需要的朋友可以參考下2014-10-10基于C#實(shí)現(xiàn)的屏幕指定區(qū)域截屏代碼
這篇文章主要介紹了C#實(shí)現(xiàn)的屏幕指定區(qū)域截屏代碼,有需要的朋友可以參考一下2014-01-01解決unity rotate旋轉(zhuǎn)物體 限制物體旋轉(zhuǎn)角度的大坑
這篇文章主要介紹了解決unity rotate旋轉(zhuǎn)物體 限制物體旋轉(zhuǎn)角度的大坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04c#創(chuàng)建Graphics對(duì)象的三種方法
通常我們使用下述三種方法來(lái)創(chuàng)建一個(gè)Graphics對(duì)象。2013-05-05c#代碼自動(dòng)修改解決方案下任意文件實(shí)例
這篇文章主要介紹了c#代碼自動(dòng)修改解決方案下任意文件實(shí)例,有需要的朋友可以參考一下2013-11-11C#實(shí)現(xiàn)簡(jiǎn)易猜數(shù)字游戲
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)簡(jiǎn)易猜數(shù)字游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04使用C#發(fā)送Http請(qǐng)求實(shí)現(xiàn)模擬登陸實(shí)例
本文主要介紹了使用C#發(fā)送Http請(qǐng)求實(shí)現(xiàn)模擬登陸實(shí)例,模擬登陸的原理簡(jiǎn)單,想要了解的朋友可以了解一下。2016-10-10