对[yield]的浅究到发现[async][await]

  上篇对[foreach]的浅究到发现[yield]写完后,觉得对[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 ThreadPool.QueueUserWorkItem((state1) =>
7 {
8 Console.WriteLine("[One] async Continue!");
9 Console.WriteLine("[One] do something!");
10 callback("Called Two");
11 });
12 }
13 public void funcTwo(CallBack callback)
14 {
15 ThreadPool.QueueUserWorkItem((state2) =>
16 {
17 Console.WriteLine("[Two] async Continue!");
18 Console.WriteLine("[Two] do something!");
19 callback("Called Three");
20 });
21 }
22 public void funcThree(CallBack callback)
23 {
24 Console.WriteLine("[Three] do something!");
25 callback("Called ...");
26 }
27 static void Main()
28 {
29 Program p = new Program();
30 p.funcOne((name1) =>
31 {
32 Console.WriteLine(name1);
33 p.funcTwo((name2) =>
34 {
35 Console.WriteLine(name2);
36 //执行funcThree
37 p.funcThree((name3) =>
38 {
39 Console.WriteLine(name3);
40 //当然还有可能继续嵌套
41 Console.WriteLine("End!");
42 });
43 });
44 });
45 Console.Read();
46 }
47 }

异步的通常实现

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

二、改进后的异步

  该[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 p.funcOne((name1) =>
8 {
9 enumerator.MoveNext();
10 });
11 yield return 1;
12 Console.WriteLine("Called Two");
13 p.funcTwo((name2) =>
14 {
15 enumerator.MoveNext();
16 });
17 yield return 2;
18 Console.WriteLine("Called Three");
19 p.funcThree((name3) =>
20 {
21 //当然还有可能继续嵌套
22 });
23 Console.WriteLine("Called ...");
24 Console.WriteLine("End!");
25 yield return 3;
26 }
27
28 //变化后的Main函数
29 static void Main()
30 {
31 enumerator.MoveNext();
32 Console.Read();
33 }

改进后的异步

  现在看看,是不是清爽了一些,没有无止尽的嵌套。代码中我们只需要定义一个迭代器,在迭代器中调用需要同步执行的方法,用[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中给出的Task解释与示例代码

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

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

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

更新:现在大家看到的是改进之后的文章,在此谢谢文章下面几位高手的讨论,让我学会了不少。抱拳!

  

对[yield]的浅究到发现[async][await],布布扣,bubuko.com

时间: 2024-08-27 03:31:33

对[yield]的浅究到发现[async][await]的相关文章

对[foreach]的浅究到发现[yield]

闲来无事,翻了翻以前的代码,做点总结,菜鸟从这里起航,呵呵. 一.List的foreach遍历 先上代码段[1]: 1 class Program 2 { 3 static void Main(string[] args) 4 { 5 List<string> dayList = new List<string> { "Sun", "Mon", "Tue", "Wed", "Thr"

理解ES7中的async/await

优势是:就是解决多层异步回调的嵌套 从字面上理解 async/await, async是 "异步"的含义,await可以认为是 async wait的简写,因此可以理解 async 用于声明一个function是异步的,而await用于等待一个异步方法执行完成返回的值(返回值可以是一个Promise对象或普通返回的值).注意:await 只能出现在 async函数中. 1-1 async的作用?首先来理解async函数是怎么处理返回值的,我们以前写代码都是通过return语句返回我们想

JavaScript 的 async/await

随着 Node 7 的发布,越来越多的人开始研究据说是异步编程终级解决方案的 async/await. 异步编程的最高境界,就是根本不用关心它是不是异步. async 函数就是隧道尽头的亮光,很多人认为它是异步操作的终极解决方案. async 和 await 起了什么作用 async 起什么作用 这个问题的关键在于,async 函数是怎么处理它的返回值的! 我们当然希望它能直接通过 return 语句返回我们想要的值,但是如果真是这样,似乎就没 await 什么事了.所以,写段代码来试试,看它到

理解 JavaScript 的 async/await

随着 Node 7 的发布,越来越多的人开始研究据说是异步编程终级解决方案的 async/await.我第一次看到这组关键字并不是在 JavaScript 语言里,而是在 c# 5.0 的语法中.C# 的 async/await 需要在 .NET Framework 4.5 以上的版本中使用,因此我还很悲伤了一阵--为了要兼容 XP 系统,我们开发的软件不能使用高于 4.0 版本的 .NET Framework. 我之前在<闲谈异步调用"扁平"化> 中就谈到了这个问题.无论

异步操作要了解的ES7的async/await

1.什么是async.await? async顾名思义是“异步”的意思,async用于声明一个函数是异步的.而await从字面意思上是“等待”的意思,就是用于等待异步完成.并且await只能在async函数中使用. 通常async.await都是跟随Promise一起使用的.为什么这么说呢?因为async返回的都是一个Promise对象同时async适用于任何类型的函数上.这样await得到的就是一个Promise对象(如果不是Promise对象的话那async返回的是什么 就是什么): awa

async await yield

问题:async 和yield有什么区别? 无奈只能用“书到用时方恨少”来解释这个问题了.其实也是自己从开始编程就接触的是nodejs中的async 以及await ,yield几乎.貌似好像都没使用过,至于它俩的区别,自己也就一知半解了,还希望看到这个问题的大神可以指教一二. 零零总总的总结一点: 1.ES6语法:async 与await搭配使用,不能拆开: 2.都是属于异步方案: 3.本质上:是解决异步编程怎么像同步编成那样写的: 4.yield :需要手动控制异步执行过程,调用.next(

理解Python协程:从yield/send到yield from再到async/await

Python中的协程大概经历了如下三个阶段: 1. 最初的生成器变形yield/send 2. 引入@asyncio.coroutine和yield from 3. 在最近的Python3.5版本中引入async/await关键字 一.生成器变形yield/send def mygen(alist): while len(alist) > 0: c = randint(0, len(alist)-1) yield alist.pop(c) a = ["aa","bb&q

浅谈Async/Await

概要 在很长一段时间里面,FE们不得不依靠回调来处理异步代码.使用回调的结果是,代码变得很纠结,不便于理解与维护,值得庆幸的是Promise带来了.then(),让代码变得井然有序,便于管理.于是我们大量使用,代替了原来的回调方式.但是不存在一种方法可以让当前的执行流程阻塞直到promise完成.JS里面,我们无法直接原地等promise完成,唯一可以用于提前计划promise完成后的执行逻辑的方式就是通过then附加回调函数. 现在随着Async/Await的增加,可以让接口按顺序异步获取数据

node.js异步控制流程 回调,事件,promise和async/await

写这个问题是因为最近看到一些初学者用回调用的不亦乐乎,最后代码左调来又调去很不直观. 首先上结论:推荐使用async/await或者co/yield,其次是promise,再次是事件,回调不要使用. 接下来是解析,为什么我会有这样的结论 首先是回调,理解上最简单,就是我把任务分配出去,当你执行完了我就能从你那里拿到结果执行相应的回调, 这里演示一个对setTimeout的封装,规定时间后打印相应结果并执行回调函数 并且这个函数传给回调函数的参数符合node标准,第一个为error信息,如果出错e