async,await執行流看不懂?看完這篇以後再也不會了

来源:https://www.cnblogs.com/huangxincheng/archive/2020/04/22/12752849.html
-Advertisement-
Play Games

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


昨天有朋友在公眾號發消息說看不懂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 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($"記錄條數:{t2.Result}");

                                                                      return t2.Result;
                                                                  });
             }).Unwrap();


            return task;
        }

-------- output -------------

記錄條數:75896

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

3. NetFramework 4.5 下 await,async的寫法

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


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

                    return Convert.ToInt32(count);
                }
            }
        }

-------- output -------------

記錄條數:75896        

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

二:案例二 【迴圈下的非同步】

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

1. NetFramework 4.0之前的寫法

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


        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 ----------------

你需要忘記失去的,感激擁有的,和期待將至的。
以前的找不到了。
對於編譯錯誤,刪除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<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>
        /// 採用遞歸處理迴圈
        /// </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 ----------------
你需要忘記失去的,感激擁有的,和期待將至的。
以前的找不到了。
對於編譯錯誤,刪除Pods文件夾然後重新pod install已經成為經驗。次。
Hello,Is there anyone here?
放鬆心情

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

3. NetFramework 4.5 下 await,async的寫法


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在經過前面八篇文章(abp(net core)+easyui+efcore實現倉儲管理系統——入庫管理之一(三十七) 至abp(net core)+easyui+efcore實現倉儲管理系統——入庫管理之八(四十四) )的學習之後,我們知道了已經基本完成了入庫管理功能。在這篇文章中我們來增加更新與刪... ...
  • 如題,納悶為什麼有空白子項並且Clear也沒用,所以搜了下,傳送門https://www.cnblogs.com/gc2013/p/4103910.html 使用的是ListView的Details視圖,提一下。 由於博主分析了很多我沒細看,因為我只是想解決這個簡單的問題,類似於直接把第一項給移除掉 ...
  • 在前面隨筆《利用微信公眾號實現商品的展示和支付(1)》介紹了商品的列表和明細信息的處理,本篇隨筆接著上一篇,繼續介紹關於商品的微信支付和購物車處理方面,其中微信支付裡面,也涉及到了獲取微信共用地址的處理,從而個更加方便錄入郵寄地址信息;購物車可以從本地的localStorage對象進行獲取和處理,也... ...
  • 實現一個基於動態代理的 AOP Intro 上次看基於動態代理的 AOP 框架實現,立了一個 Flag, 自己寫一個簡單的 AOP 實現示例,今天過來填坑了 目前的實現是基於 Emit 來做的,後面有時間再寫一個基於 Roslyn 來實現的示例 效果演示 演示代碼: 切麵邏輯定義: 測試服務定義 測 ...
  • 後端:asp.net core web api + EF Core 前端:VUE + Element-UI+ Node環境的後臺管理系統 資料庫:SQL Server2017 伺服器:阿裡雲伺服器 線上地址:http://www.wangjk.wang 賬號:admin 密碼:123 API文檔地址 ...
  • 數組類型 在 C 中,數組實際上是對象,數組是一種數據結構,它包含若幹相同類型的變數。 數組概述 數組具有以下屬性: 數組可以是 "一維" 、 "多維" 或 "交錯" 的。 數值數組元素的預設值設置為零,而引用元素的預設值設置為 null。 交錯數組是數組的數組,因此其元素是引用類型並初始化為 nu ...
  • 劍指Offer題目,求數值的整數次方,題目描述,給定一個double類型的浮點數base和int類型的整數exponent。求base的exponent次方。保證base和exponent不同時為0。包括遞歸,整數的快速冪等多種解法 ...
  • 場景 有時會遇到使用枚舉類型的時候。 比如傳遞過來一個int的list,要根據這個list將對應的chekbox選中。 首先新建一個類KillComponents public enum KillComponents { /// <summary> /// 上霧化器 /// </summary> S ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...