对[yield]的浅究到发现[async][await]
原文:对[yield]的浅究到发现[async][await]
上篇对[foreach]的浅究到发现[yield]写完后,觉得对[yield]还没有理解清楚,想起曾经看过一位大牛的帖子讲的很深刻(链接在此),回顾了下,在这里写出自己的理解,与各位分享。
一、通常的异步
现在我们假设一种平时经常遇到的情况,现有三个方法,其中funcOne和funcTwo比较耗时需要异步执行,而且他们的逻辑是必须在funcOne执行完后才可以执行funcTwo,同理funcTwo执行完后才能执行funcThree。
按照这样的设定,通常的做法请看代码段[1]:
public class Program
{
public delegate void CallBack(string nextName);
public void funcOne(CallBack callback)
{
Console.WriteLine("[One] async Continue!");
Console.WriteLine("[One] do something!");
callback("Called Two");
}
public void funcTwo(CallBack callback)
{
Console.WriteLine("[Two] async Continue!");
Console.WriteLine("[Two] do something!");
callback("Called Three");
}
public void funcThree(CallBack callback)
{
Console.WriteLine("[Three] do something!");
callback("Called ...");
}
static void Main()
{
Program p = new Program();
//异步执行funcOne
ThreadPool.QueueUserWorkItem((state1)=>{
p.funcOne((name1) =>
{
Console.WriteLine(name1);
//异步执行funcTwo
ThreadPool.QueueUserWorkItem((state2) =>
{
p.funcTwo((name2) =>
{
Console.WriteLine(name2);
//执行funcThree
p.funcThree((name3) =>
{
Console.WriteLine(name3);
//当然还有可能继续嵌套
Console.WriteLine("End!");
});
});
});
});
});
Console.Read();
}
}
异步的通常实现
相信看完代码后我们的感觉是一样的,好繁琐,就是不断的嵌套!那有没有方法可以避免这样呢,也就是说用同步的写法来写异步程序。
二、改进后的异步
该[yield]粉墨登场了,先看代码段[2]:
//三个方法以及委托CallBack的定义不变,此处不再列出。
//新增了静态的全局变量enumerator,和静态方法funcList.
public static System.Collections.IEnumerator enumerator = funcList();
public static System.Collections.IEnumerator funcList()
{
Program p = new Program();
//异步执行funcOne
ThreadPool.QueueUserWorkItem((state1) =>
{
p.funcOne((name1) =>
{
enumerator.MoveNext();
});
});
yield return ;
Console.WriteLine("Called Two");
//异步执行funcTwo
ThreadPool.QueueUserWorkItem((state2) =>
{
p.funcTwo((name2) =>
{
enumerator.MoveNext();
});
});
yield return ;
Console.WriteLine("Called Three");
//执行funcThree
p.funcThree((name3) =>
{
//当然还有可能继续嵌套
});
Console.WriteLine("Called ...");
Console.WriteLine("End!");
yield return ;
} //变化后的Main函数
static void Main()
{
enumerator.MoveNext();
Console.Read();
}
改进后的异步写法
现在看看,是不是清爽了一些,没有无止尽的嵌套。代码中我们只需要定义一个迭代器,在迭代器中调用需要同步执行的方法,用[yield]来分隔,各方法通过在callback里调用迭代器的MoveNext()方法来保持同步。
通过这样的实践,我们可以理解为每当[yield return ..],程序会把迭代器的[上下文环境]暂时保存下来,等到MoveNext()时,再调出来继续执行到下一个[yield return ..]。
三、是我想太多
以上纯属瞎扯,在.net 4.5之后,我们有了神器:async/await,下面看看多么简洁吧。
代码段[3]:
public class Program
{
public async Task funcOne()
{
Console.WriteLine("[One] async Continue!");
Console.WriteLine("[One] do something!");
//await ...
}
public async Task funcTwo()
{
Console.WriteLine("[Two] async Continue!");
Console.WriteLine("[Two] do something!");
//await ...
}
public void funcThree()
{
Console.WriteLine("[Three] do something!");
}
public static async Task funcList()
{
Program p = new Program();
await p.funcOne();
await p.funcTwo();
p.funcThree();
//无尽的嵌套可以继续await下去。
Console.WriteLine("End!");
}
static void Main()
{
funcList();
Console.Read();
}
}
async/await
我已经感觉到了您的惊叹之情。
async修饰符将方法指定为异步方法(注意!:异步不异步,并不是async说了算,如果这个方法中没有await语句,就算用了async修饰符,它依然是同步执行,因为它就没有异步基因)。
被指定为异步方法后,方法的返回值只能为Task、Task<TResult>或者void,返回的Task对象用来表示这个异步方法,你可以对这个Task对象进行控制来操作这个异步方法,详细的可以参考msdn中给出的Task解释与示例代码。
await用于挂起主线程(这里的主线程是相对的),等待这个异步方法执行完成并返回,接着才继续执行主线程的方法。用了await,主线程才能得到异步方法返回的Task对象,以便于在主线程中对它进行操作。如果一个异步方法调用时没有用await,那么它就会去异步执行,主线程不会等待,就像我们代码段[3]中Main方法里对funcList方法的调用那样。
最后就分析到这儿吧,希望各位兄弟博友能一起讨论,共同进步。
当然,别吝啬您的[赞]哦 :)
对[yield]的浅究到发现[async][await]的更多相关文章
- 对[foreach]的浅究到发现[yield]
原文:对[foreach]的浅究到发现[yield] 闲来无事,翻了翻以前的代码,做点总结,菜鸟从这里起航,呵呵. 一.List的foreach遍历 先上代码段[1]: class Program { ...
- 理解ES7中的async/await
理解ES7中的async/await 优势是:就是解决多层异步回调的嵌套 从字面上理解 async/await, async是 "异步"的含义,await可以认为是 async w ...
- async await 的 实质 本质
async await 的 实质 就是 用 “状态机” 来 取代 函数层层调用 . async await 的 本质 是 语法糖, 和 提高性能 什么的 没什么关系 . 为了避免理解歧义, 我把 ...
- 我 支持 使用 async await
这篇文章原来的 标题 是 <我 反对 使用 async await>, 但经过后来的一些研究, 发现 async await 是 良性 的, 所以 我把 标题 改成了 <我 支持 使 ...
- [转] 理解 JavaScript 的 async/await
[From] https://segmentfault.com/a/1190000007535316 边城 2016年11月19日发布 随着 Node 7 的发布,越来越多的人开始研究据说是 ...
- 深入理解理解 JavaScript 的 async/await
原文地址:https://segmentfault.com/a/1190000007535316,首先感谢原文作者对该知识的总结与分享.本文是在自己理解的基础上略作修改所写,主要为了加深对该知识点的理 ...
- 七 vue学习 async/await
1: javaScript async/await: 调用async函数的时候,是异步的,函数后面的代码继续执行.! async / await是ES7的重要特性之一,也是目前社区里公认的优秀异步解 ...
- 理解 JavaScript 的 async/await
随着 Node 7 的发布,越来越多的人开始研究据说是异步编程终级解决方案的 async/await.我第一次看到这组关键字并不是在 JavaScript 语言里,而是在 c# 5.0 的语法中.C# ...
- 深入理解协程(三):async/await实现异步协程
原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的最后一篇. 从本篇你将了解到: ...
随机推荐
- XXTEA 加密算法 C++ C#兼容版本号
1.一个不错的可逆加密算法XXTEA 之前无意中看到了TexturePacker 使用了XXTEA来加密图片资源.所以花了点时间来看了下XXTEA. 一般有两种加密算法:1.像md5,SHA1,等ha ...
- RunJS推荐用于个人使用(使用方便JS、css实时预览、编辑、管理等功能)
RunJS,在线编写.展示html.js.css代码,拥有实时预览.分享.Fork.代码高亮.自己主动完毕等多项特性,提供文件上传.多种登录方式. 地址:http://runjs.cn/ waterm ...
- 认识input输入框的placeholder属性
我们来认识下input输入框的placeholder属性. placeholder 属性提供可描述输入字段预期值的提示信息.(placeholder 属性适用于以下的 <input> 类型 ...
- Following unknown configure options were used:--enable-fpm
跑cd php-5.2.13安装时间 ./configure --prefix=/usr/local/php/ --with-config-file-path=/usr/local/php/etc ...
- 使用shell/python获取hostname/fqdn释疑(转)
一直以来被Linux的hostname和fqdn(Fully Qualified Domain Name)困惑了好久,今天专门抽时间把它们的使用细节弄清了. 一.设置hostname/fqdn 在Li ...
- 关闭 MsMpEng.exe
MsMpEng.exe是Windows Defender 自动保护服务的核心引擎. 系统是win8.1 最近发现MsMpEng.exe是任务管理器里面最占内存的一个程序,且无法强制结束程序.偶然发现一 ...
- 实现android里面WebView显示内容
在日常学习.我们会看到,当手机应该检查注册协议.单击协议时,以查看内部协议的全部内容! 以下给大家看看实现的过程: 首先贴show_xy.XML代码: <WebView android:layo ...
- UVa 10190 - Divide, But Not Quite Conquer!
称号:给你第一个任期的等比数列和倒数公比,最后一个条目假定1这一系列的输出,否则输出Boring!. 分析:数学.递减的.所以公比的倒数一定要大于1.即m > 1. 然后在附加一个条件n &g ...
- ORDER BY RAND()
大概是因为需要研究了一下MYSQL随机样本实现.例如:离tablename表随机抽取了创纪录,我们一般的写法是:SELECT * FROM tablename ORDER BY RAND() LIMI ...
- 7 Ways to earn money on programming(转)
英文原文:7 Ways to earn money on programming 几个星期前,当我收到一个自称 Someone712 的人发给我的一条消息时,我决定要写一篇如何用编程赚钱的博客文章.S ...