下一代C#里的async和await

C#发展至今,已经从最初的1.0到了4.0版本,不如来回顾一下各个版本都带来了什么:

  1. 1.0版本 - 基本C#语法。
  2. 2.0版本 - 泛型的支持,CLR进行了升级,从根本上支持了运行时泛型。
  3. 3.0版本 - LINQ,添加了from / join等类SQL关键字,添加了扩展函数,添加了编译期动态类型var关键字。
  4. 4.0版本 - dynamic关键字,CLR进行升级,加入DLR,开始对动态进行友好的支持。同时加入动态参数、参数默认值、泛型协变等特性。

可以看到,C#从诞生至今,经历2次CLR的升级,以及1次语法层面的扩展,其作为一个语言已经非常便利、强大。但是随着时代的发展,C#依旧在不断前进,而下一代C# vNext又即将诞生。每一代的C#都会在小的语法调整之外,带来一个震撼性的特性。从2.0的泛型、3.0的查询到4.0的动态,每一个版本的C#都有着一个主导的思想,而其他细节的改进和调整则是围绕着这个最基本的思想给予支持。

在这样一路明确的有且只有一个主导思想的升级路线上,下一代的C# vNext的核心思想又是什么呢?纵观当下的软件工程界,最热门的话题莫过于并行计算,为此C#早在4.0版本中就已经引入了Parallel Linq扩展,简化并行的开发。但是这远远不够,即便Parallel Linq已经提供了极大的便利,但其执行-回调模型依旧打破了编码人员以往对代码就是一行一行顺序执行的习惯思维。因此,C# vNext的主导思想是在这之上再给予更多的进化,即C# vNext将着眼于:

异步

C# vNext为了将异步变得更为简单,引入了2个关键字,asyncawait,下面简单介绍下这2个关键字给我们的编程带来怎么样的改变。

以一个标准的逻辑为例:下载一个远程URI,并将内容输出在界面上,假设我们已经有了显示内容的方法:

void Display(string text) {
    // 不管是怎么实现的
}

如果用标准的同步式写法,这代码相当之容易:

void ShowUriContent(string uri) {
    using (WebClient client = new WebClient()) {
        string text = client.DownloadString(uri);
        Display(text);
    }
}

当然这不是我们讨论的重点,同步方式会造成线程的阻塞,必须选择WebClient下载完成才可以继续运行,如果这个过程在UI线程上执行,则会造成UI无响应的情况。同时网络是非常不可预测的外部条件,很可能因为网络状况不好导致程序长时间没有响应,显然不是我们希望得到的结果。

所以我们又有了异步的方案,.NET中最早的异常编程模式是Begin/End模式,不过WebClient作为WebRequest的高层封装,已经把这个模式给封装了:

void DownloadUri(string uri) {
    using (WebClient client = new WebClient()) {
        client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(ShowContent);
        client.DownloadStringAsync(uri);
    }
}

void ShowContent(object sender, DownloadStringCompletedEventArgs e) {
    Display(e.Result);
}

看看,好好的事情一变成异步,就变得麻烦无比。一个很明确逻辑的方法活生生拆成2个来处理,虽然可以用Lambda或者delegate来使代码上进行简化,但依旧无可避免一段逻辑被拆成两段的痛苦。当更多的异步操作交叉在一起的时候,无论是代码的组织还是逻辑的梳理都会变得更加麻烦。

正因为如此,C# vNext引入了关键了,从语法上对此进行了改进,当使用asyncawait时,我们的代码会变成这样:

void async ShowUriContent(string uri) {
    using (WebClient client = new WebClient()) {
        string text = await client.DownloadStringTaskAsync(uri);
        Display(text);
    }
}

悄悄地告诉你,我写上面这段代码的时候,是直接把同步方案的代码复制过来再稍微发了几个字符的……由此可见,在语言级别给予支持后,代码的编写将会是如何地顺畅和简便。这段代码看上去就是一段典型的同步逻辑,创建-下载-显示按部就班,唯一不同地就是在方法声明中加入了async关键字,在DownloadStringTaskAsync方法的调用时加入了await关键字。就这么神奇地,运行时变成了异步。ShowUriContent方法会在调用DownloadStringTaskAsync后退出,而下载过程会异步进行,当下载完成后,再进入Display方法的执行,期间不会阻塞线程,不会造成UI无响应的情况。

虽然高手们总是说不要关心语言,不要在意语言,真正重要的是思想。但是看着这样的代码,真的还能认为语言的优秀与否对生产效率没有影响吗?

至于如何实现这个效果,本篇并不想做太多的说明,因为本文的目的仅仅是向大家介绍一下下一代C#的一个特性。实现机制方面,相信大家都想得到,编译器会将方法体在await关键字前后打断,编译为Begin/End模式的异步模型。这并不是什么难事,但是能想到并付诸于实施却并不容易。至少JAVA7虽然强化了异步编程,但却没有让语言达到这样的程度。请不要不屑于语法糖,正如高手们所说,无论什么语言都不见得能改变设计的代价,那么实现过程的效率,就决定了项目本身的生产效率。

说回来,这个思想和老赵的[Jscex](http://blog.zhaojie.me/tag/Jscex/ 老赵点滴 - 追求编程之美)非常类似,都是试图通过一步编译,将异步的编程模型统一为同步模型,简化开发复杂度,提升生产效率。时至如今,还想说中国的程序员搞不出创造性的东西吗?

PS1:怎么去体验下C# vNext。

  1. 装备好Visual Studio 2010 + SP1,无论什么版本。
  2. Visual Studio Async CTP下载下来,并安装。
  3. 建个项目,现在你已经可以使用asyncawait关键字了,而诸如WebClient下的DownloadStringTaskAsync方法,则是在%MyDocument%\Microsoft Visual Studio Async CTP\Samples\AsyncCtpLibrary.dll下定义的扩展方法。

关于具体的实践和原理,可以看一看[C# 5.0 vNext - New Asynchronous Pattern](http://www.codeproject.com/KB/cs/async.aspx CodeProject)一文。

PS:最后说说为什么我要写这一篇。原本我是不想写关于.NET的内容的,毕竟已经有不短的时间游走在.NET社区的边缘,没有深入地研究,并不适合来发表一些自己的论点。但是看到近段时间博客园首页上依旧遍历着诸如“C#最新特性”这样的文章时,真的觉得很不舒服。C# 4.0已经出来多久了,C# 5.0都离我们只有多少距离了,我相信关于Async CTP的内容有不少喜欢逛国外博客的园友是接触过的,但是却没有一个人愿意将这些最前沿的消息分享过来……

当然我也并不认为这个社区的每一员都有义务将自己所知道的内容分享出来,但是现在国内的.NET社区确实存在着这样的现状:大家分享的多数是已经被嚼得稀巴烂的骨头,什么“C#的可变参数”,什么“自己写一个AJAX实现”,这些或许对你个人的学习有着历史性的意义,但是这样已经存在、流传已久,几乎家喻户晓的概念,在博客园首页这样的位置传播,真的有其意义所在吗?而这些最前沿的变化、那些更加深入的探究,或者是没人接触,或者就是接触了但不愿意分享。这并不是我所希望的社区状态,如今的互联网,无论是SNS还是微博,大家都在注重着消息的传播这一环节,为什么在.NET社区里,却是死气沉沉的状态,把旧菜炒了又炒,满眼都见不到一丝亮点?

posted @ 2011-09-07 17:52 Gray Zhang 阅读(3172) 评论(27) 编辑 收藏

 回复 引用 查看   
#1楼2011-09-07 18:26 | 卡索      
干货,值得顶起来...
 回复 引用 查看   
#2楼2011-09-07 18:45 | chenkai      
现在刚推出CTP版本/,这个不仅是这个关键字.把更多的异步操作交给交给编译器去做....
 回复 引用 查看   
#3楼[楼主]2011-09-07 18:55 | Gray Zhang      
@chenkai
关键字正是因为有编译器的支持才称其为关键字吧……

 回复 引用 查看   
#4楼2011-09-07 18:55 | chenkai      
Visual Studio Async CTP 1 我安装10扁都没成功过.
后来没办法 把所有的VS2010 SP1重新卸载.在安装才成功..........64位操作系统好像还不支持.

 回复 引用 查看   
#5楼2011-09-07 19:21 | toEverybody      
唉呀。。。。。这C#究竞是一个什么玩意儿。。。就象在玩什么语言花样一样。。。总是没有见它做出什么大事来。。。看看C/C++,Delphi.....根本就没有它漂亮,却为我们干了好多的事情。生产了好多的让人佩服的产品。
C#10年了。。。难道还年轻吗??
等老赵来。。。。

 回复 引用 查看   
#6楼2011-09-07 19:52 | jiaxingseng      
我以为C# 5这点事儿早就成了“嚼得稀巴烂的骨头”了。。。毕竟是。。。多长时间以前?一年?两年?前公布的了。。。
 回复 引用 查看   
#7楼[楼主]2011-09-07 19:53 | Gray Zhang      
@jiaxingseng
不,远比这个更早……按MS团队里某人的说法,这东西其实在VS2003时代就已经有了……只是根本没人关注

 回复 引用 查看   
#8楼2011-09-07 20:02 | chenkai      
@Gray Zhang
是关注的人太少. CTP 1这个版本也存在一定问题也是事实.

 回复 引用 查看   
#9楼2011-09-07 20:10 | 浅水鱼      
灰哥也写.net 支持支持..
 回复 引用 查看   
#10楼2011-09-07 21:17 | 诺贝尔      
没有正式版的东西不敢用。
 回复 引用 查看   
#11楼2011-09-07 21:24 | Homer_Simpson      
有没有人来说说都用C#开发哪些类型的软件?
 回复 引用 查看   
#12楼[楼主]2011-09-07 21:51 | Gray Zhang      
@诺贝尔
微软的CTP至少顶一般公司的beta版,微软的beta版基本就是一般公司的正式版水准了……

 回复 引用 查看   
#13楼2011-09-07 22:02 | testzhangsan      
引用PS:最后说说为什么我要写这一篇。原本我是不想写关于.NET的内容的,毕竟已经有不短的时间游走在.NET社区的边缘,没有深入地研究,并不适合来发表一些自己的论点。但是看到近段时间博客园首页上依旧遍历着诸如“C#最新特性”这样的文章时,真的觉得很不舒服。C# 4.0已经出来多久了,C# 5.0都离我们只有多少距离了,我相信关于Async CTP的内容有不少喜欢逛国外博客的园友是接触过的,但是却没有一个人愿意将这些最前沿的消息分享过来……

当然我也并不认为这个社区的每一员都有义务将自己所知道的内容分享出来,但是现在国内的.NET社区确实存在着这样的现状:大家分享的多数是已经被嚼得稀巴烂的骨头,什么“C#的可变参数”,什么“自己写一个AJAX实现”,这些或许对你个人的学习有着历史性的意义,但是这样已经存在、流传已久,几乎家喻户晓的概念,在博客园首页这样的位置传播,真的有其意义所在吗?而这些最前沿的变化、那些更加深入的探究,或者是没人接触,或者就是接触了但不愿意分享。这并不是我所希望的社区状态,如今的互联网,无论是SNS还是微博,大家都在注重着消息的传播这一环节,为什么在.NET社区里,却是死气沉沉的状态,把旧菜炒了又炒,满眼都见不到一丝亮点?

都忙着赶工期。

 回复 引用 查看   
#14楼2011-09-08 00:21 | Jeffrey Zhao      
引用toEverybody:
唉呀。。。。。这C#究竞是一个什么玩意儿。。。就象在玩什么语言花样一样。。。总是没有见它做出什么大事来。。。看看C/C++,Delphi.....根本就没有它漂亮,却为我们干了好多的事情。生产了好多的让人佩服的产品。
C#10年了。。。难道还年轻吗??
等老赵来。。。。

来了,居然说C#没有干出过大事来,别故意找骂,都懒得骂你了。
继续保持状态,等我心情好点就来骂你啊。

 回复 引用 查看   
#15楼2011-09-08 00:22 | Jeffrey Zhao      
怎么可能没有人分享过这个东西,显然我一年前就谈过了,哈哈:
http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-1.html

 回复 引用 查看   
#16楼2011-09-08 09:10 | 口丁@携程研发中心      
vs2012 ctp版马上要推出了
 回复 引用 查看   
#17楼2011-09-08 09:15 | 顾客      
@Jeffrey Zhao
期待老赵出口~

 回复 引用 查看   
#18楼2011-09-08 09:29 | 码码浒浒      
时至如今,还想说中国的程序员搞不出创造性的东西吗?
你创造出了什么? 求解?
反正我没见过... 把一种事物换种玩法 或 招数 就叫创造? 悲剧了~~~

虽然我们没能力创造,但是 如果能接触到核心,理解它 ,并 用它 来做些其他的事情 估计这充其量 就是 山寨一下而已.

PS:TX 这么一个小偷公司 都说 人家 已经 “创造” 出....了,我就真服了.曾经还有些人 为此辩解的 颇有艺术感,更可恨的是 有人信了 我擦...

其实我等待的是 atomic 关键字,呜呼~~
 回复 引用 查看   
#20楼[楼主]2011-09-08 10:29 | Gray Zhang      
@码码浒浒
敢问当下计算机技术有哪一个能跳出冯式体系和图灵完备性的约束的?哪一个不是在这两大理论的基础上做出变换而形成的?你试图说明的创造想举个例子不?

 回复 引用 查看   
#21楼2011-09-08 11:09 | 码码浒浒      
@Gray Zhang
你没分清楚 创造 和 变形 的区别~~~~ 不解释
"当下" 还是 活在当下吧....
1:lamb dynamic 的出现,
2:用 lamb dynamic 举一反三 或 重构,甚至借助第三方来搞个大改动... 变形!
PS:1:暴雪游戏模式和思想 2:TX的游戏模式和思想

 回复 引用 查看   
#22楼[楼主]2011-09-08 11:13 | Gray Zhang      
@码码浒浒
嗯,我可以看到你更认同模式和思想作为一种创新,而对这种模式或者思想的实现过程的优化并不被你认同的样子……
但是能不能再换一个角度看,我们的实现过程,比如说编程,也是一种模式呢?“写程序的模式和思想”是不是也是一种“模式和思想”呢?将原本需要100行的代码,通过改变编写的模式变成10行,或者将原本要1-3-5-7这样读的,通过模式的改变成为1-2-3-4这样很顺眼的方式,我个人还是认为这也是一种创新的

另外,dynamic也无非是把一抓一大把的动态语言拿进来,而lambda更是存在不知多少年月,甚至比计算机的历史还老的数学概念……实现lambda就和实现+-*/一样,纯粹是把数学里的一个运算符在计算机语言里做个映射……

 回复 引用 查看   
#23楼2011-09-08 11:36 | 码码浒浒      
@Gray Zhang
有同意之处 例如:GoF 设计模式 的确如此

 回复 引用 查看   
#24楼2011-09-08 11:38 | 码码浒浒      
发完 我笑了 结果还是模式.... 你说的 我部分认同 It's true.
 回复 引用 查看   
#25楼2011-09-08 11:51 | NewObject      
一篇 好文,却被一堆评争论论搞坏了气氛,自身没见识过的就说没有? 文章识其意为最佳,何必咬文。
 回复 引用 查看   
#26楼[楼主]2011-09-08 12:08 | Gray Zhang      
@NewObject
没事,我就是来找骂的……按理在.NET社区我不应该发表这种言论,毕竟我的水平是不够格的,只是对园子首页的质量确实有所不满,只是从自己的想法和角度,想表明一下希望园子首页应该有怎么样的内容……

 回复 引用 查看   
#27楼2011-09-09 08:49 | suxin      
@toEverybody
其实我觉得你是故意在耍宝,背地里肯定在用C#