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('成功信息') ) ...
随机推荐
- 《深入理解 Java 虚拟机》读书笔记:Java 内存模型与线程
正文 由于计算机的处理器运算速度与它的存储和通信子系统速度的差距太大了,大量的时间都花费在磁盘 I/O.网络通信或者数据库访问上,导致处理器在大部分时间里都处于等待其他资源的状态.因此,为了充分利用计 ...
- SVM | 支持向量机原理讲解(二)
一.线性可分的支持向量机存在的问题 在支持向量机一中,我们介绍了当数据集是线性可分的时候,我们可以使用线性可分的支持向量机将数据进行分类(由于隔了很长时间才更新,因此忘记了支持向量机一的读者可以回看支 ...
- coding++:Spring_IOC(控制反转)详解
IoC是什么: 1):Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想. 2):在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的 ...
- coding++ :javascript Date format (js日期格式化)
方式一: // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符, // 年(y)可以用 1 ...
- Jmeter 中 Bean Shell 之全局变量
1.新建测试计划>线程组 > http 请求 -登录 获取token , 可以参照我以前写的这篇博客 https://www.cnblogs.com/cyit/p/12632445.htm ...
- python——新excel模块之openpyxl
1.安装 pip install openpyxl 2.新建文件 book=openpyxl.Workbook() 3.打开sheet页(两种方式) sheet=book.active #默认的she ...
- Visio2013 专业版激活码和激活工具 亲测有效
Visio2013密钥 专业版:Visio Professional 2013 KEY C2FG9-N6J68-H8BTJ-BW3QX-RM3B3 2NYF6-QG2CY-9F8XC-GWMBW-29 ...
- MATLAB 文件读取(3)
1.gps ,数值格式的读取 clear all test=importdata('2017- 9-27- 8-26-51.txt'); [r,c]=size(test.data);%row行,col ...
- 使用Shiro+JWT完成的微信小程序的登录(含讲解)
使用Shiro+JWT完成的微信小程序的登录 源码地址https://github.com/Jirath-Liu/shiro-jwt-wx 微信小程序用户登陆,完整流程可参考下面官方地址,本例中是按此 ...
- Mac 开发工具信息的备份
相信大部分程序员都对开发环境的工具都有一些特殊的执念(???),如果在自己不习惯的环境中工作完全无法开展,怎么这个工具没有那个字体难受,我本人就是,换了新的 Mac 电脑后如何快速恢复到之前的开发工具 ...