原文:对[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]的更多相关文章

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

    原文:对[foreach]的浅究到发现[yield] 闲来无事,翻了翻以前的代码,做点总结,菜鸟从这里起航,呵呵. 一.List的foreach遍历 先上代码段[1]: class Program { ...

  2. 理解ES7中的async/await

    理解ES7中的async/await 优势是:就是解决多层异步回调的嵌套 从字面上理解 async/await, async是 "异步"的含义,await可以认为是 async w ...

  3. async await 的 实质 本质

    async await  的 实质 就是 用 “状态机” 来 取代 函数层层调用 . async await  的 本质 是 语法糖,  和 提高性能 什么的 没什么关系 . 为了避免理解歧义, 我把 ...

  4. 我 支持 使用 async await

    这篇文章原来的 标题 是 <我 反对 使用 async await>, 但经过后来的一些研究, 发现 async await 是 良性 的, 所以 我把 标题 改成了 <我 支持 使 ...

  5. [转] 理解 JavaScript 的 async/await

    [From] https://segmentfault.com/a/1190000007535316      边城 2016年11月19日发布 随着 Node 7 的发布,越来越多的人开始研究据说是 ...

  6. 深入理解理解 JavaScript 的 async/await

    原文地址:https://segmentfault.com/a/1190000007535316,首先感谢原文作者对该知识的总结与分享.本文是在自己理解的基础上略作修改所写,主要为了加深对该知识点的理 ...

  7. 七 vue学习 async/await

    1:  javaScript async/await: 调用async函数的时候,是异步的,函数后面的代码继续执行.! async / await是ES7的重要特性之一,也是目前社区里公认的优秀异步解 ...

  8. 理解 JavaScript 的 async/await

    随着 Node 7 的发布,越来越多的人开始研究据说是异步编程终级解决方案的 async/await.我第一次看到这组关键字并不是在 JavaScript 语言里,而是在 c# 5.0 的语法中.C# ...

  9. 深入理解协程(三):async/await实现异步协程

    原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的最后一篇. 从本篇你将了解到: ...

随机推荐

  1. .NET 4 并行(多核)编程系列之二 从Task开始

    原文:.NET 4 并行(多核)编程系列之二 从Task开始 .NET 4 并行(多核)编程系列之二 从Task开始 前言:我们一步步的从简单的开始讲述,还是沿用我一直的方式:慢慢演化,步步为营.   ...

  2. [Android 4.4.4] 泛泰A870 通过刷第三版 Mokee4.4.4 KTU84P 20140626 RC2.1 by syhost

    主题及注意事项请访问以前的版本: http://blog.csdn.net/syhost/article/details/29931291 此RC2.1版比RC2.0改进的地方: 1. Mokee本身 ...

  3. HDU 1710-Binary Tree Traversals(二进制重建)

    Binary Tree Traversals Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/O ...

  4. jquery之ajax中国乱码的解决方案

    $.ajax({ dataType : 'json',type : 'POST',url : 'http://localhost/test/test.do',data : {id: 1, type: ...

  5. OpenGL中shader使用

    学了接近一个月的OpenGL,最终要排上用场了...好吧,就从学到的shader(着色器)开刀吧. 先简单的介绍shader,shader事实上是显卡的功能,就是利用显卡的GPU去做图像处理的工作,而 ...

  6. Android Activity之间通信

    package com.example.myapp; import android.app.Activity; import android.content.DialogInterface; impo ...

  7. Mybatis分页插件更新

    分页插件演示:http://blog.csdn.net/isea533/article/details/23831273 分页插件演示样例:http://blog.csdn.net/isea533/a ...

  8. 实现BUG自动检测 - ASP.NET Core依赖注入

    我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评. 如果以后有时间的话,我打算写一个系列的[实现BUG自动检测 ...

  9. SQL Server 文件路径

    原文:SQL Server 文件路径 系统数据库文件路径 master <drvie>:\program files\microsoft sql server\mssql10.<in ...

  10. PHP操作数据库PDO

    PHP操作数据库 载入数据库驱动 訪问phpinfo.php能够查看是否已经载入数据库驱动,例如以下显示还没有载入mySql数据库驱动. 在c盘找到php.ini配置文件开启载入mySql驱动,例如以 ...