C# 5新特性详解之一——异步编程 转。。保存一下以后看

转载 2012年03月27日 13:57:28

C# 5新特性详解之一——异步编程

2012-03-26 13:08 | 5619次阅读 | 来源:CSDN 【已有35条评论】发表评论

关键词:C# | 作者:王然 | 收藏这篇资讯

导读:本文详细介绍了C#5的新特性:异步编程、方法调用、Lambda表达式..,供开发者参阅。

在即将到来的新的Windows Runtime中更根本地确定任何API都不会运行超过50ms的时间。需要更长时间的操作将会由'kick off this operation'API来代替,不等待运算结果就直接立刻返回。这样做是因为Microsoft希望Windows8 Metro程序能够在即时的触控UI上能够“快速并且流动”,因为触控操作上即使是微小的停顿相比于用鼠标或者键盘来操作都会变得更加明显。从UI的角度来说,这是一项很有帮助的设计方案。

但是从开发者的角度来说,它会使编程变得更加麻烦。当我们读取文件或者调用WCF服务时,我们通常希望能够影响到结果。如果能够保证读取文件或者WCF服务返回时结果肯定可获得的,我们由上而下地写出容易理解和推理的代码。

  1. string url = ReadUrlFromFile(filename); 
  2. string contentOfUrl = HttpGetFromUrl(url); 
  3. MessageBox.Show(contentOfUrl); 

这样的API被叫做同步或者阻塞。同步API易于理解和使用,不过在你的程序内部当前线程没有反应时,API就无法控制你的代码去做其它任务,因为它还不能传递结果。

拥使用即时返回的'kick off' API的方式叫做异步或者无阻塞。使用异步API编程更加繁难,因为你不能即时将结果返回给变量来保证运行:

  1. string url = BeginReadUrlFromFile(filename);  // Won't work -- file read hasn't completed when BeginRead returns 
  2. string contentOfUrl = BeginHttpGetFromUrl(url);  // Ditto 
  3. MessageBox.Show(contentOfUrl);

相反,你不得不回调需要使用返回结果的代码,直到它已经准备好了:

  1. BeginReadUrlFromFile(filename, url => { 
  2.     BeginHttpGetFromUrl(url, contentOfUrl => { 
  3.       MessageBox.Show(contentOfUrl); 
  4.     }); 
  5.   }); 

甚至于这样一个简单的例子都显得相当丑陋。实际上,异步代码中需要更多的运算,更复杂的回调,逻辑条件,early exits以及错误处理,所以会更加难看。.NET框架中真正的异步API更加丑陋,到处都是 IAsyncResult对象和成对的EndXxx方法调用。

然而,如果我们希望能程序在Windows Runtime中运行,这就是用户所希望我们做的。

原来的解决方案:使用F#

F#背后聪明的人们想出来一个两全其美的解决方案。F#有一个叫做异步工作流程的特色功能,它由很多块异步引进的代码块组成。在异步工作流程中,你可以通过使用一个很像同步的语法来调用异步方法:

  1. async { 
  2.   let! url = BeginReadUrlFromFile filename 
  3.   let! contentOfUrl = BeginHttpGetFromUrl url 
  4.   MessageBox.Show(contentOfUrl) 

F#编译器自动将这易于阅读、理解的代码转变为可怕的回调式等价物,这样你就可以简单地使用异步调用的响应行为从上而下地编程。

新的解决方案:使用C# 5

C#背后也有同样聪明的人,所以新的C#中也实现了这项功能。Visual Studio 11 beta中包含的下一版本的C#进了两个新关键字——"async" 和 "await"

关键字"async"表明使用的是异步调用方法。这对于调用者来说,理解它非常重要,因为这意味着方法会在它结束前返回——方法能够在异步调用时中途放弃而直接返回给它的调用者。

关键字"await"表明我们希望保证自上而下的逻辑 异步调用 而不是手动编写回调函数。下面是他们完美结合在一起的例子:

  1. public async void ShowReferencedContent(string filename) { 
  2.   string url = await BeginReadFromFile(filename); 
  3.   string contentOfUrl = await BeginHttpGetFromUrl(url); 
  4.   MessageBox.Show(contentOfUrl); 

这样比回调更方便读、写和检查,但他们的作用完全相同。(实际上,这确实比回调更智能些,因为编译器并不会因为厌烦而跳过错误状况或者弄错early exit逻辑又或者忽略线程错误。)

当我们调用方法时发生了什么?首先是调用BeginReadFromFile方法,它提供了文件名和编译器生成的回调。BeginReadFromFile迅速返回,但结果仍然不可得。所以结果仍然不能分配给URL变量——回调的一部分——然后方法退出,返回给调用者!调用函数重新运行,并且保持它的代码持续运行,尽管被调用方法还没有结束。

然后在晚点时候,文件系统完成了阅读操作。这意味着结果现在是可获得的,Runtime安排回调。这并不一定会立刻发生——具体的时间还依赖于同步的环境。回调函数运行着,捆将URL变量和文件操作的结果绑定,然后调用BeginHttpGetFromUrl。它也会立刻返回,也就是说,方法会再一次退出。

最后,HTTP操作完成,回调函数第二次运行。它将绑定Url变量的内容和显示结果的消息框如果(如果有的话)。

我会希望向调用者返回什么值?

Async methods can exit before they’ve finished. So if an async method wants to return a result, it has to recognise that it might return to the caller before that result is available. For this reason, an async method that returns a value has to have a return type of Task rather than a ‘proper’ value. A Task represents a chunk of work which will eventually deliver a value, so a caller can examine the returned Task to determine when the result becomes available. Here’s how an async method looks when returning a value:

异步方法能够在结束前退出,所以,如果一个异步方法希望返回一个结果就不得不确认它是否在得到结果前就返回给调用者。因此,一个返回值的异步方法不得不包含一个Task返回类型而不是一个“合适的”值。一个Task代表最终会传递值的很大一块工作,所以调用者也能坚持返回的Task来确定什么时候会得到结果。下面是一个返回值的异步方法的样子:

  1. public static async Task<string> GetReferencedContent(string filename) 
  2.   string url = await BeginReadFromFile(filename); 
  3.   string contentOfUrl = await BeginHttpGetFromUrl(url); 
  4.   return contentOfUrl; 
  5. }

注意:尽管返回类型是Task<string>,返回状态接收的是一条字符串。再一次,编译器来管理返回状态产生一个Task。

现在调用者能够直接调用GetReferencedContent方法或者等待字符串变为可得,或者手动让它等待,又或者使它提前结束——无论如何它都适合使用结果。

Async-friendly APIs

如果你习惯在.NET 4或者更早之前版本上使用异步编程,你会习惯成对地使用Begin和End方法,比如WebRequest.BeginGetResponse 和WebRequest.EndGetResponse。这在.NET4.5中依然存在,但它们不使用await关键字。(主要是因为BeginXxx方法需要在回调中使用确切的方法调用来得到结果,而且编译器并不依赖EndXxx命名规范).NET4.5提供了返回Task对象的新方法,所以你可以调用WebRequest.GetResponseAsync来代替WebRequest.BeginGetResponse方法。下面是一个.NET4.5中使用异步API的一个实例:

  1. private static async Task<string> GetContent(string url) 
  2.   WebRequest wr = WebRequest.Create(url); 
  3.   var response = await wr.GetResponseAsync(); 
  4.   using (var stm = response.GetResponseStream()) 
  5.   { 
  6.     using (var reader = new StreamReader(stm)) 
  7.     { 
  8.       var content = await reader.ReadToEndAsync(); 
  9.       return content; 
  10.     } 
  11.   } 

这和使用 WebRequest.GetResponse() 和 TextReader.ReadToEnd()的同步代码是如此相似,只需要在API名后加上Async并且在方法前加上"await"关键字就可以了,相信你很快就能掌握它。

C# 5 新特性深入浅出:详解异步编程

【IT168 技术】导读:本文详细介绍了C#5的新特性:异步编程、方法调用、Lambda表达式..,供开发者参阅。   在即将到来的新的Windows Runtime中更根本地确定任何API都不会运行...
  • zzy7075
  • zzy7075
  • 2012年04月01日 19:40
  • 389

JDK5新特性之线程池(一)

一. 线程池的概念: 其实到目前为止我们接触过很多关于池的概念:string池、连接池,之所以要用这个池,目的只有一个:资源的重复使用。 线程池:首先创建一些线程,当服务器接收到一个客户请求后,就从线...
  • zdp072
  • zdp072
  • 2014年10月24日 10:30
  • 1098

Extjs5.0新特性

http://docs.sencha.com/ext/5.0.0/whats_new/5.0/whats_new.html 用google简单翻译了 不是专业人士,不喜勿喷。    我们很...
  • xingjing315
  • xingjing315
  • 2014年07月01日 15:27
  • 1863

Hibernate5总结及新特性

1. 明确Hibernate是一个实现了ORM思想的框架,它封装了JDBC,是程序员可以用对象编程思想来操作数据库。 2. 明确ORM(对象关系映射)是一种思想,JPA(Java Persistenc...
  • elementf
  • elementf
  • 2017年06月09日 14:13
  • 575

C# 5.0五大新特性

第一:绑定运算符,:=: 这个只是简化了数据绑定,跟ASP.NET MVC3不断改进一样,其实不是什么亮点改进。 comboBox1.Text :=: textBox1.Text; //将文本框的...
  • mss359681091
  • mss359681091
  • 2017年01月12日 14:15
  • 3293

【Servlet3.0新特性】第01节_Servlet注解及异步支持

完整版见https://jadyer.github.io/2013/06/24/servlet30-new-feature/
  • jadyer
  • jadyer
  • 2013年06月24日 20:10
  • 1746

C#异步编程基础入门总结

异步这概念刚开始接触的时候,不是那么容易接受,但是需要用的地方还真的挺多的,刚学习的时候,也很懵逼走了不少弯路,所以这里有必要总结一下。...
  • kebi007
  • kebi007
  • 2017年08月23日 15:54
  • 1778

C# 并行编程 之 异步编程模型

异步编程模型的使用
  • wangzhiyu1980
  • wangzhiyu1980
  • 2015年06月17日 09:21
  • 1099

关于C#5.0异步编程与6.0新特性的总结

C#5.0作为第五个C#的重要版本,将异步编程的易用度推向一个新的高峰。通过新增的async和await关键字,几乎可以使用编写同步代码的方式来编写异步代码。 本文将重点介绍下新版C#的异步特性...
  • aa2397199142
  • aa2397199142
  • 2016年08月18日 13:59
  • 1309

C#的异步编程模式

第一步: 对于任何需要进行异步调用的方法,需要定义一个委托。为什么需要这个?按照我的理解是对于异步操作一般是在另外一个线程中执行方法的代码块,而委托所传递的相当于是函数的指针。即将委托传递给...
  • wenzhang1992
  • wenzhang1992
  • 2017年04月30日 15:13
  • 302
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C# 5新特性详解之一——异步编程 转。。保存一下以后看
举报原因:
原因补充:

(最多只允许输入30个字)