用户登录
用户注册

分享至

一文搞懂c# await,async执行流

  • 作者: 爱美小姑凉
  • 来源: 51数据库
  • 2022-04-30

昨天有朋友在公众号发消息说看不懂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=utf-8;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=utf-8;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=utf-8;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=utf-8;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=utf-8;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返回给调用端即可,如果没看明白,我画一张图吧!

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

3. netframework 4.5 下 await,async的写法

😄,刚刚是不是噩梦般经历,救世主来啦,还是要鱼和熊掌一起兼得

 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=utf-8;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那种垃圾般代码所实现的功能,我都想仰天长啸,我太难了。

三:总结

还是那句话,你没有被伤过,永远不会体会到那种刻骨铭心的痛。

以上就是一文搞懂c# await,async执行流的详细内容,更多关于c# await,async执行流的资料请关注其它相关文章!

软件
前端设计
程序设计
Java相关