async,await执行流看不懂?看完这篇以后再也不会了(async和await的执行顺序)

网友投稿 276 2022-08-15

async,await执行流看不懂?看完这篇以后再也不会了(async和await的执行顺序)

一:案例一 【嵌套下的异步】

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

{

var messageList = new List();

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> 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();

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;

}

///

/// 采用递归处理循环

///

///

///

///

public static Task> GetMessageList(MySqlDataReader reader, List 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());

}

}).Unwrap();

return task;

}

}

------------ output ----------------

你需要忘记失去的,感激拥有的,和期待将至的。

以前的找不到了。

对于编译错误,删除Pods文件夹然后重新pod install已经成为经验。次。

Hello,Is there anyone here?

放松心情

在递归下探的过程中把messageList集合给填满了,而后将messageList返回给调用端即可,如果没看明白,我画一张图吧!

3. NetFramework 4.5 下 await,async的写法

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:C# ORM学习笔记:T4入门及生成数据库实体类(cctv5体育节目表)
下一篇:C#将DataTable数据导出CSV文件(c罗)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~