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('成功信息') ) ...
随机推荐
- 使用SparkSQL编写wordCount的词频统计
# 使用SparkSQL编写wordCount的词频统计 ## word.txt```hello hello scala sparkjava sql html java hellojack jack ...
- PAT-B 1003. 我要通过!(20) Java版
"答案正确"是自动判题系统给出的最令人欢喜的回复.本题属于PAT的"答案正确"大派送 -- 只要读入的字符串满足下列条件,系统就输出"答案正确&quo ...
- 特征选择与稀疏学习(Feature Selection and Sparse Learning)
本博客是针对周志华教授所著<机器学习>的"第11章 特征选择与稀疏学习"部分内容的学习笔记. 在实际使用机器学习算法的过程中,往往在特征选择这一块是一个比较让人模棱两可 ...
- 150+行Python代码实现带界面的数独游戏
150行代码实现图形化数独游戏 Github地址,欢迎各位大佬们fork.star啥的,感谢: 今天闲着没事干,以前做过html+js版的数独,这次做个python版本的,界面由pygame完成,数独 ...
- python入门灵魂5问--python学习路线,python教程,python学哪些,python怎么学,python学到什么程度
一.python入门简介 对于刚接触python编程或者想学习python自动化的人来说,基本都会有以下python入门灵魂5问--python学习路线,python教程,python学哪些,pyth ...
- Python实现压缩解压缩,移动复制copy文件
import shutil import os from shutil import make_archive # 查看可压缩的文件类型 print(shutil.get_archive_format ...
- vue+express+mongodb 实现 增删改查
一.创建一个vue项目 用脚手架vue-cli搭建一个项目,数据请求用axios方式,写几个按钮用来调接口(vue这块不做多解释,不懂的可以先去官网学习vue-cli:https://cli.vuej ...
- 你还不知道Vue的生命周期吗?带你从Vue源码了解Vue2.x的生命周期(初始化阶段)
作者:小土豆biubiubiu 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.im/user/58c61b4361ff4b005d9e8 ...
- JDBC获取连接抛出java.sql.SQLException: The server time zone...
今天尝试数据库,代码确实没问题就是给了给这个东西 java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecogniz ...
- vue中使用阿里图标库iconfont和在旧有的iconfont中添加新的图标
第一步 下载样式http://www.iconfont.cn/选择图表,点击加入购物车 第二步 解压下载文件 第三步 修改文件名称 与 iconfont.css 名路径 第四步 将@font-face ...