async,await执行流看不懂?看完这篇以后再也不会了
昨天有朋友在公众号发消息说看不懂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的写法
async,await执行流看不懂?看完这篇以后再也不会了的更多相关文章
- 看完这篇,再也不怕被问到 AsyncTask 的原理了
本文很多资料基于Google Developer官方对AsyncTask的最新介绍. AsyncTask 是什么 AsyncTask is designed to be a helper class ...
- 看完这篇。再也不怕被问 HandlerThread 的原理
HandlerThread是什么 官网介绍 A Thread that has a Looper. The Looper can then be used to create Handlers. No ...
- 8张图让你一步步看清 async/await 和 promise 的执行顺序
摘要: 面试必问 原文:8张图帮你一步步看清 async/await 和 promise 的执行顺序 作者:ziwei3749 Fundebug经授权转载,版权归原作者所有. 为什么写这篇文章? 说实 ...
- 8 张图帮你一步步看清 async/await 和 promise 的执行顺序(转)
https://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651555491&idx=1&sn=73779f84c289d9 ...
- async/await 执行顺序详解
随着async/await正式纳入ES7标准,越来越多的人开始研究据说是异步编程终级解决方案的 async/await.但是很多人对这个方法中内部怎么执行的还不是很了解,本文是我看了一遍技术博客理解 ...
- promise async await使用
1.Promise (名字含义:promise为承诺,表示其他手段无法改变) Promise 对象代表一个异步操作,其不受外界影响,有三种状态: Pending(进行中.未完成的) Resolved( ...
- JS中的async/await的执行顺序详解
虽然大家知道async/await,但是很多人对这个方法中内部怎么执行的还不是很了解,本文是我看了一遍技术博客理解 JavaScript 的 async/await(如果对async/await不熟悉 ...
- promise和async await的区别
在项目中第一次遇到async await的这种异步写法,来搞懂它 项目场景 :点击登录按钮后执行的事件,先进行表单校验 this.$refs.loginFormRef.validate(element ...
- Promise 和async/await 的使用理解
Promise 和async/await 的使用理解 1. new Promise时就会开始执行语句. new Promise(resolve => resolove('成功信息') ) ...
随机推荐
- JDBC开源框架:DBUtils自定义业务类型相关转换器
dbutils提供的handler转换不能满足实际业务开发的需求.比如枚举转int,时间类型LocalDateTime,实体对象的属性名与字段未能相对应. mysql表member结构字段: id.m ...
- python之面向对象的成员,方法,属性,异常处理
一.类的私有成员 1. 类中的私有成员是什么? 私有:只有满足一部分条件的才能使用 私有类的属性 私有对象的属性 私有方法 正常状态 class B: school_name = '老男孩教育' de ...
- 常见Web安全漏洞--------sql注入
SQL注入:利用现有应用程序,将(恶意)的SQL命令注入到后台数据库执行一些恶意的操作.在mybatis 中比较容易出现:${} 会发生sql 注入问题 #{}: 解析为一个 JDBC 预编译语句(p ...
- JVM 常见参数配置
-XX:+PrintGC 每次触发GC的时候打印相关日志 -XX:+PrintGCDetails 每次触发GC的时候更详细的相关日志 -XX:+UseSerialGC 串行回收 -Xms 堆初始值( ...
- iOS 响应链
一.UIResponder app 使用响应者对象接收和处理事件,只有继承 UIResponder 的类,才能处理事件. UIApplication.UIView.UIViewController 都 ...
- python中的原地操作
什么是原地操作: 例子: 列表在append添加一个元素后,没有产生新副本,再次打印的时候多了一个值,这个appned就是原地操作 由此可见,原地操作有以下特点: 没有返回值(返回值为None) 改变 ...
- 一夜搞懂 | JVM 字节码执行引擎
前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 一.为什么要学习字节码执行引擎? 代码编译的结果从本地机器码转变为字节码,是存储格式发展的一 ...
- 《Three.js 入门指南》3.1.1 - 基本几何形状 - 球体(SphereGeometry)
3.1 基本几何形状 球体(SphereGeometry) 构造函数: THREE.SphereGeometry(radius, segmentsWidth, segmentsHeight, phiS ...
- jQuerry点击按钮回到顶部功能
简单实现点击按钮回到顶部功能
- Spring 中使用 WebSocket 笔记
编写 WebSocket 消息处理类,比较简单的方式就是直接继承AbstractWebSocketHandler,并覆写其中的处理方法,下面为一个简单的 demo public class WebSo ...