博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
对[yield]的浅究到发现[async][await]
阅读量:6612 次
发布时间:2019-06-24

本文共 5124 字,大约阅读时间需要 17 分钟。

原文:

  上篇写完后,觉得对[yield]还没有理解清楚,想起曾经看过一位大牛的帖子讲的很深刻(),回顾了下,在这里写出自己的理解,与各位分享。

一、通常的异步

  现在我们假设一种平时经常遇到的情况,现有三个方法,其中funcOne和funcTwo比较耗时需要异步执行,而且他们的逻辑是必须在funcOne执行完后才可以执行funcTwo,同理funcTwo执行完后才能执行funcThree。

  按照这样的设定,通常的做法请看代码段[1]:

1      public class Program 2      { 3          public delegate void CallBack(string nextName); 4          public void funcOne(CallBack callback) 5          { 6              Console.WriteLine("[One] async Continue!"); 7              Console.WriteLine("[One] do something!"); 8              callback("Called Two"); 9          }10          public void funcTwo(CallBack callback)11          {12              Console.WriteLine("[Two] async Continue!");13              Console.WriteLine("[Two] do something!");14              callback("Called Three");15          }16          public void funcThree(CallBack callback)17          {18              Console.WriteLine("[Three] do something!");19              callback("Called ...");20          }21          static void Main()22          {23              Program p = new Program();24              //异步执行funcOne25              ThreadPool.QueueUserWorkItem((state1)=>{26                  p.funcOne((name1) =>27                  {28                      Console.WriteLine(name1);29                      //异步执行funcTwo30                      ThreadPool.QueueUserWorkItem((state2) =>31                      {32                          p.funcTwo((name2) =>33                          {34                              Console.WriteLine(name2);35                              //执行funcThree36                              p.funcThree((name3) =>37                              {38                                  Console.WriteLine(name3);39                                  //当然还有可能继续嵌套40                                  Console.WriteLine("End!");41                              });42                          });43                      });44                  });45              });46              Console.Read();47          }48      }
异步的通常实现

  相信看完代码后我们的感觉是一样的,好繁琐,就是不断的嵌套!那有没有方法可以避免这样呢,也就是说用同步的写法来写异步程序。

二、改进后的异步

  该[yield]粉墨登场了,先看代码段[2]:

1     //三个方法以及委托CallBack的定义不变,此处不再列出。 2     //新增了静态的全局变量enumerator,和静态方法funcList. 3     public static System.Collections.IEnumerator enumerator = funcList(); 4       public static System.Collections.IEnumerator funcList() 5         { 6             Program p = new Program(); 7             //异步执行funcOne 8             ThreadPool.QueueUserWorkItem((state1) => 9             {10                 p.funcOne((name1) =>11                 {12                     enumerator.MoveNext();13                 });14             });15             yield return 1;16             Console.WriteLine("Called Two");17             //异步执行funcTwo18             ThreadPool.QueueUserWorkItem((state2) =>19             {20                 p.funcTwo((name2) =>21                 {22                     enumerator.MoveNext();23                 });24             });25             yield return 2;26             Console.WriteLine("Called Three");27             //执行funcThree28             p.funcThree((name3) =>29             {30                 //当然还有可能继续嵌套31             });32             Console.WriteLine("Called ...");33             Console.WriteLine("End!");34             yield return 3;35         }36 37       //变化后的Main函数38       static void Main()39         {40             enumerator.MoveNext();41             Console.Read();42         }
改进后的异步写法

  现在看看,是不是清爽了一些,没有无止尽的嵌套。代码中我们只需要定义一个迭代器,在迭代器中调用需要同步执行的方法,用[yield]来分隔,各方法通过在callback里调用迭代器的MoveNext()方法来保持同步。

  通过这样的实践,我们可以理解为每当[yield return ..],程序会把迭代器的[上下文环境]暂时保存下来,等到MoveNext()时,再调出来继续执行到下一个[yield return ..]。

三、是我想太多

  以上纯属瞎扯,在.net 4.5之后,我们有了神器:async/await,下面看看多么简洁吧。

  代码段[3]:

 

1      public class Program 2     { 3         public async Task funcOne() 4         { 5             Console.WriteLine("[One] async Continue!"); 6             Console.WriteLine("[One] do something!"); 7             //await ... 8         } 9         public async Task funcTwo()10         {11             Console.WriteLine("[Two] async Continue!");12             Console.WriteLine("[Two] do something!");13             //await ...14         }15         public void funcThree()16         {17             Console.WriteLine("[Three] do something!");18         }19         public static async Task funcList()20         {21             Program p = new Program();22             await p.funcOne();23             await p.funcTwo();24             p.funcThree();25             //无尽的嵌套可以继续await下去。26             Console.WriteLine("End!");27         }28         static void Main()29         {30             funcList();31             Console.Read();32         }33     }
async/await

 

  我已经感觉到了您的惊叹之情。

  async修饰符将方法指定为异步方法(注意!:异步不异步,并不是async说了算,如果这个方法中没有await语句,就算用了async修饰符,它依然是同步执行,因为它就没有异步基因)。

  被指定为异步方法后,方法的返回值只能为Task、Task<TResult>或者void,返回的Task对象用来表示这个异步方法,你可以对这个Task对象进行控制来操作这个异步方法,详细的可以参考msdn中给出的。

  await用于挂起主线程(这里的主线程是相对的),等待这个异步方法执行完成并返回,接着才继续执行主线程的方法。用了await,主线程才能得到异步方法返回的Task对象,以便于在主线程中对它进行操作。如果一个异步方法调用时没有用await,那么它就会去异步执行,主线程不会等待,就像我们代码段[3]中Main方法里对funcList方法的调用那样。

 

  最后就分析到这儿吧,希望各位兄弟博友能一起讨论,共同进步。

  当然,别吝啬您的[赞]哦 :)

 

 

  

 

转载地址:http://jrxso.baihongyu.com/

你可能感兴趣的文章
QuickBI助你成为分析师——数据源FAQ小结
查看>>
十周三次课
查看>>
S/4HANA服务订单Service Order的批量创建
查看>>
2008 AD 复制有防火墙要开什么端口
查看>>
IT服务管理中的知识库建设
查看>>
【Lucene】Lucene通过CustomScoreQuery实现自定义评分
查看>>
linux 内核网络,数据接收流程图
查看>>
我的友情链接
查看>>
在windows下与linux虚拟机进行文件共享
查看>>
php 图形用户界面GUI 开发
查看>>
正则表达式详解
查看>>
LeetCode问题5
查看>>
AIX系列------ISO挂载
查看>>
如何打开被管理员禁止的注册表编辑器
查看>>
java根据经纬度计算距离
查看>>
CF976D. Degree Set
查看>>
我的友情链接
查看>>
Nginx 在window server 2008R2上装有IIS启动不了
查看>>
Python运行效率低的原因
查看>>
NSD基础交换-子网划分
查看>>