async,await执行流看不懂?看完这篇以后再也不会了
昨天有朋友在公眾號發(fā)消息說看不懂a(chǎn)wait,async執(zhí)行流,其實(shí)看不懂太正常了,因?yàn)槟銢]經(jīng)過社會的毒打,沒吃過牢飯就不知道自由有多重要,沒生過病就不知道健康有多重要,沒用過ContinueWith就不知道await,async有多重要,下面我舉兩個(gè)案例佐證一下?
一:案例一 【嵌套下的異步】
寫了這么多年的程序,相信大家都知道連接數(shù)據(jù)庫少不了這幾個(gè)對象,DbConnection,DbCommand,DbDataReader等等。。先來看看ContinueWith在連接數(shù)據(jù)庫時(shí)嵌套過深的尷尬。
1. NetFramework 4.0之前的寫法
這個(gè)時(shí)期的代碼沒有什么好說的,都是程式代碼,一擼到底,簡潔明了。
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ù):758962. NetFramework 4.0下ContinueWith的寫法
當(dāng)年異步和并發(fā)編程概念特別火,火熱度參考現(xiàn)在的直播帶貨,這個(gè)時(shí)期的C#率先使用新的Task一網(wǎng)兜,在數(shù)據(jù)庫操作的幾大類中開始有了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)對漸進(jìn)式的Async方法,我不得不進(jìn)行ContinueWith的深層嵌套,如果Async更多,那對可讀性將是毀滅性的打擊,這就是所謂的回調(diào)地獄。
3. NetFramework 4.5 下 await,async的寫法
寫到這里讓我想起了邢老大的那本自傳書《左手夢想,右手療傷》,這苦這心酸只有真正經(jīng)歷過的人才會懂,沒有人能夠隨隨便便成功,接下來大家的期望就是如何做到有同步式的代碼又有異步功效,魚和熊掌我都要,當(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上面這代碼太簡潔了,眼花的朋友還以為是同步代碼呢?改造的地方也僅僅是方法簽名處加上一個(gè)async,異步方法前加上await,相當(dāng)于痛苦版的ContinueWith。
二:案例二 【循環(huán)下的異步】
上一個(gè)案例只是使用ExecuteScalarAsync從數(shù)據(jù)庫中讀取一個(gè)值來得到表中的記錄數(shù),在業(yè)務(wù)開發(fā)中更多的是使用ExecuteReader從數(shù)據(jù)庫中獲取批量記錄,這個(gè)就涉及到了如何在循環(huán)中使用異步,想想就太苦難了(┬_┬)。
1. NetFramework 4.0之前的寫法
這里我從messages表中讀取5條記錄,然后輸出到控制臺,詳細(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 ----------------你需要忘記失去的,感激擁有的,和期待將至的。 以前的找不到了。 對于編譯錯(cuò)誤,刪除Pods文件夾然后重新pod install已經(jīng)成為經(jīng)驗(yàn)。次。 Hello,Is there anyone here? 放松心情2. NetFramework 4.0下ContinueWith的寫法
要想用ContinueWith完成這功能,最簡單有效的辦法就是使用遞歸,用遞歸的方式把若干個(gè)ContinueWith串聯(lián)起來,而要用遞歸的話還要單獨(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 ---------------- 你需要忘記失去的,感激擁有的,和期待將至的。 以前的找不到了。 對于編譯錯(cuò)誤,刪除Pods文件夾然后重新pod install已經(jīng)成為經(jīng)驗(yàn)。次。 Hello,Is there anyone here? 放松心情在遞歸下探的過程中把messageList集合給填滿了,而后將messageList返回給調(diào)用端即可,如果沒看明白,我畫一張圖吧!
3. NetFramework 4.5 下 await,async的寫法
????,剛剛是不是噩夢般經(jīng)歷,救世主來啦,還是要魚和熊掌一起兼得。
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 ---------------- 你需要忘記失去的,感激擁有的,和期待將至的。 以前的找不到了。 對于編譯錯(cuò)誤,刪除Pods文件夾然后重新pod install已經(jīng)成為經(jīng)驗(yàn)。次。 Hello,Is there anyone here? 放松心情天底下還有如此簡潔的代碼就可以實(shí)現(xiàn)ContinueWith那種垃圾般代碼所實(shí)現(xiàn)的功能,我都想仰天長嘯,我太難了。
三:總結(jié)
還是那句話,你沒有被傷過,永遠(yuǎn)不會體會到那種刻骨銘心的痛。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的async,await执行流看不懂?看完这篇以后再也不会了的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 7种方法帮助企业改进软件维护效率
- 下一篇: 如何分析EFCore引发的内存泄漏