歡迎您光臨本站 註冊首頁

一文搞懂c# await,async執行流

←手機掃碼閱讀     qp18502452 @ 2020-06-12 , reply:0

昨天有朋友在公眾號發消息說看不懂await,async執行流,其實看不懂太正常了,因為你沒經過社會的毒打,沒吃過牢飯就不知道自由有多重要,沒生過病就不知道健康有多重要,沒用過ContinueWith就不知道await,async有多重要,下面我舉兩個案例佐證一下?

一:案例一 【嵌套下的異步】
 

寫了這麼多年的程序,相信大家都知道連接數據庫少不了這幾個對象,DbConnection,DbCommand,DbDataReader等等。。先來看看ContinueWith在連接數據庫時嵌套過深的尷尬。

1. NetFramework 4.0之前的寫法
 

這個時期的代碼沒有什麼好說的,都是程式代碼,一擼到底,簡潔明瞭。

   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($"記錄條數:{count}");       return Convert.ToInt32(count);    }    }   }

 

output

記錄條數:75896

2. NetFramework 4.0下ContinueWith的寫法
 

當年異步和併發編程概念特別火,火熱度參考現在的直播帶貨,這個時期的C#率先使用新的Task一網兜,在數據庫操作的幾大類中開始有了Async結尾的方法,如OpenAsync,ExecuteScalarAsync,ReadAsync 等等,但遺憾的是那時寫異步,只能像下面這樣寫。

   public static TaskContinueWithGetCount()   {    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($"記錄條數:{t2.Result}");             return t2.Result;           });    }).Unwrap();        return task;   }

 

output

記錄條數:75896

相比同步代碼,這異步代碼寫的是不是很憋屈,為了應對漸進式的Async方法,我不得不進行ContinueWith的深層嵌套,如果Async更多,那對可讀性將是毀滅性的打擊,這就是所謂的回調地獄。

3. NetFramework 4.5 下 await,async的寫法

寫到這裡讓我想起了邢老大的那本自傳書《左手夢想,右手療傷》,這苦這心酸只有真正經歷過的人才會懂,沒有人能夠隨隨便便成功,接下來大家的期望就是如何做到有同步式的代碼又有異步功效,魚和熊掌我都要,當然是可以的,看看如何用await,async進行改造。

   public static async TaskAsyncGetCount()   {    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($"記錄條數:{count}");       return Convert.ToInt32(count);    }    }   }

 

output

記錄條數:75896

上面這代碼太簡潔了,眼花的朋友還以為是同步代碼呢? 改造的地方也僅僅是方法簽名處加上一個async,異步方法前加上await,相當於痛苦版的ContinueWith。

二:案例二 【循環下的異步】

上一個案例只是使用ExecuteScalarAsync從數據庫中讀取一個值來得到表中的記錄數,在業務開發中更多的是使用ExecuteReader從數據庫中獲取批量記錄,這個就涉及到了如何在循環中使用異步,想想就太苦難了(┬_┬)。

1. NetFramework 4.0之前的寫法

這裡我從messages表中讀取5條記錄,然後輸出到控制檯,詳細代碼如下:

   public static ListSyncGetMessageList()   {    var messageList = new List();    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

你需要忘記失去的,感激擁有的,和期待將至的。
 以前的找不到了。
 對於編譯錯誤,刪除Pods文件夾然後重新pod install已經成為經驗。次。
 Hello,Is there anyone here?
 放鬆心情    

2. NetFramework 4.0下ContinueWith的寫法

要想用ContinueWith完成這功能,最簡單有效的辦法就是使用遞歸,用遞歸的方式把若干個ContinueWith串聯起來,而要用遞歸的話還要單獨定義一個方法,寫的有點亂,大家將就著看吧。

   public class Program   {   public static void Main(string[] args)   {    var task = ContinueWithAsyncGetMessageList();      task.Result.ForEach(Console.WriteLine);      Console.Read();   }     public static Task<List> 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();       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;   }     ////// 採用遞歸處理循環   ////////////public static Task<List> GetMessageList(MySqlDataReader reader, ListmessageList)   {    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());     }    }).Unwrap();      return task;   }   }

 

output

你需要忘記失去的,感激擁有的,和期待將至的。
 以前的找不到了。
 對於編譯錯誤,刪除Pods文件夾然後重新pod install已經成為經驗。次。
 Hello,Is there anyone here?
 放鬆心情    

在遞歸下探的過程中把messageList集合給填滿了,而後將messageList返回給調用端即可,如果沒看明白,我畫一張圖吧!

在遞歸下探的過程中把messageList集合給填滿了,而後將messageList返回給調用端即可,如果沒看明白,我畫一張圖吧!

3. NetFramework 4.5 下 await,async的寫法

剛剛是不是噩夢般經歷,救世主來啦,還是要魚和熊掌一起兼得

   public static async Task<List> AsyncGetMessageList()   {    var messageList = new List();    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

你需要忘記失去的,感激擁有的,和期待將至的。
 以前的找不到了。
 對於編譯錯誤,刪除Pods文件夾然後重新pod install已經成為經驗。次。
 Hello,Is there anyone here?
 放鬆心情    

天底下還有如此簡潔的代碼就可以實現ContinueWith那種垃圾般代碼所實現的功能,我都想仰天長嘯,我太難了。

三:總結
 

還是那句話,你沒有被傷過,永遠不會體會到那種刻骨銘心的痛。

 


[qp18502452 ] 一文搞懂c# await,async執行流已經有373次圍觀

http://coctec.com/docs/c/language/show-post-238285.html