内容简介:昨天有朋友在公众号发消息说看不懂await,async执行流,其实看不懂太正常了,因为你没经过社会的毒打,没吃过牢饭就不知道自由有多重要,没生过病就不知道健康有多重要,没用过ContinueWith就不知道await,async有多重要,下面我举两个案例佐证一下?写了这么多年的程序,相信大家都知道连接数据库少不了这几个对象,DbConnection,DbCommand,DbDataReader等等。。先来看看ContinueWith在连接数据库时嵌套过深的尴尬。这个时期的代码没有什么好说的,都是程式代码,一
昨天有朋友在公众号发消息说看不懂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的写法
:smile:,刚刚是不是噩梦般经历,救世主来啦,还是要鱼和熊掌一起兼得。
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那种垃圾般代码所实现的功能,我都想仰天长啸,我太难了。
三:总结
还是那句话,你没有被伤过,永远不会体会到那种刻骨铭心的痛。
如您有更多问题与我互动,扫描下方进来吧~
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 老师,你确定Java注释不会被执行吗?
- 面试官:不会看 Explain 执行计划,简历敢写 SQL 优化?
- C# 永远不会返回的方法真的不会返回
- “Oracle 不会放弃 Java!”
- 还学不会webpack?看这篇
- 我去,你竟然还不会用 synchronized
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
从规范出发的程序设计
[美] Carroll Morgan / 裘宗燕 / 机械工业出版社 / 2002-8 / 45.00元
本书详细论述了有关规范程序设计的内容,包括:程序和精化、谓词演算、选择、迭代、构造类型、模块和封装等,最后几章还包含了大量的实例研究和一些更高级的程序设计技术。本书提倡一种严格的程序开发方法,分析问题要用严格方式写出程序的规范,而后通过一系列具有严格理论基础的推导,最终得到可以运行的程序。 本书是被世界上许多重要大学采用的教材,适于计算机及相关专业的本科生和研究生使用。一起来看看 《从规范出发的程序设计》 这本书的介绍吧!