伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 教育考试 » 文章详细 订阅RssFeed

async,await执行流看不懂?看完这篇以后再也不会了

来源:本站原创 浏览:87次 时间:2022-12-19
一:案例一 【嵌套下的异步】

写了这么多年的程序,相信大家都知道连接数据库少不了这几个对象,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的写法

刚刚是不是噩梦般经历,救世主来啦,还是要鱼和熊掌一起兼得。


       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 ----------------
你需要忘记失去的,感激拥有的,和期待将至的。
以前的找不到了。
对于编译错误,删除Pods文件夹然后重新pod install已经成为经验。次。
Hello,Is there anyone here?
放松心情

天底下还有如此简洁的代码就可以实现ContinueWith那种垃圾般代码所实现的功能,我都想仰天长啸,我太难了。

三:总结

还是那句话,你没有被伤过,永远不会体会到那种刻骨铭心的痛。


  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net