.NET中的“.NET研究”异步编程:使用F#简化异步编程

  不管是使用yield或借助第三方类库来简化异步编程,或多或少总是感觉不那么正统,有点hack的感觉。这种感觉在实验阶段倒还可以,要是用在产品中总有点担心,即使这些类库来自权威的第三方,我不知道大家有没有跟我同样的感觉。那么这个时候我们就会想,如果在语言中直接能提供这种机制该多好呢。

  F#的异步工作流

  在Visual Studio 2010中,新包含了一种语言:F#。F#的一大特性就是异步计算。能让你用同步的方式编写异步的代码,不用使用AsyncCallback回调将一个方法分为两段,也不用注册异步完成事件。

  F#是一个强类型的函数式编程语言,现在是2.0版本,在VS2010中正式作为first-class语言出现。其主要设计者是Don Syme,同是.NET中的泛型的主要设计者之一。

  我们来看看前面几篇文章中都包含的那个示例使用F#的代码将是怎样:


let asyncDownload (url:string) =
  async{
let req = WebRequest.Create(url)
let! resp = req.AsyncGetResponse()
  use stream
= resp.GetResponseStream()
let reader = new StreamReader(stream)
  return reader.ReadToEnd()
  }

  很短小精悍吧(实际上这段代码可以更短,但为了说明异步的编写方式,我没有使用那些看起来有点怪的语法)。下面我们来解读一下这段代码,希望本文结束后你能对F#中的异步有点初步的印象。

  F#中用let定义一个值,比如:


let value = 5

  不过上面的代码是用let定义一个函数。不过请记住,F#是函数式编程语言,在这里函数也是值。观察上面的代码,let后面是函数名,然后跟着函数的参数列表(url : string)。F#有强大的类型推断能力,一般情况下参数的类型是不需要写的,但是在这个代码中因为WebRequest.Create方法有多个重载方式,所以无法推断出url的类型,需要加上string。注意这里定义类型的方式。

  下面是本问最有趣的地方了:async{…}。这就是所谓的异步工作流,它实际上是AsyncBuilder的一个全局示例。而被包括在asyn上海闵行企业网站设计与制作c{}内的一些操作被转换为FSharpAsyncBuilder的方法调用,这种使用方式在F#里称之为工作流(Workflow)。注意,这和业务系统中的工作流程系统是不同的。关于工作流我会在下一篇文章中详细介绍。现在我们只需要知道async{}执行的结果放回的是一个Asynca(泛型)类型的东西,这个东西表示一个可以被调度运行的任务,我们可以这样使用这个方法:


Async.RunSynchronously(asyncDownload("http://www.google.com"))

  Async.RunSynchronously会将asyncDownload返回的这个异步任务放到线程池中执行,然后阻塞线程等待返回结果。

  在这里需要说明的是,前面下载网页内容的代码是异步执行的。当调用req.AsyncGetResponse时只是注册异步回调,但是并不阻塞线程。当从远程服务器拿到响应后会接着执行req.AsyncGetResponse后面的内容。这样就用非常自然的同步顺序的方式,编写出异步的代码。这比之前使用各种第三方类库的hack方式看起来更自然。至于这种方式背后的实现原理,敬请期待下篇文章。

  但这里存在一个问题是,如果我们现在的场景是这样的:

  在Winform窗体上有一个按钮,点击按钮后下载网页内容,然后将内容显示在页面上的一个文本框中。那么这里使用Async.RunSynchronously就不是个好注意。RunSynchronously会阻塞UI线程直到返回结果,那么我们在本系列开始的时候提到构建灵敏的UI的目的就没有达到。我们不能阻塞UI线程,应该让它执行完毕后调用我们的代码将内容显示在文本框中。幸好Async提供了StartWithContinuations方法,我们就可以这样来执行我们的下载程序了:

上海徐汇企业网站设计与制作>


Async.StartWithContinuations(asyncDownload("http://www.google.com",上海企业网站制作
  (func html
- textBox.Text = html),
  (func ex
- MessageBox.Show(ex.Message))
  (func canl
- MessageBox.Show("canceled"))

  Async.StartWithContinuations第一个参数接收的是我们异步执行的任务,然后接收三个回调。这三个回调就是我在.NET中的异步编程(三)- Continuation passing style以及使用yield实现异步中介绍的continuation。它上海闵行企业网站制作们分别是成功执行后将怎样(在textBox中显示),发生异常后怎样(使用MessageBox显示警告),以及任务被取消了将怎样。使用这个后这里就不再有阻塞了,continuation是在asyncDownload执行完毕后触发的,不是通过阻塞线程等来的。

  实际上在textBox中显示html源代码这个回调不再是在UI线程上工作了,聪明的你应该知道这样会抛出不在创建控件的线程上修改控件的属性的异常,但是奇怪的是这里却没有抛出这个异常,这都是StartWithContinuations的功劳,它在开始运行的时候会捕获当前程序的上下文(SynchronizationContext),然后在执行continuations的时候会在原来捕获的上下文中执行代码,所以也就不会抛出那个异常了。

  req.AsyncGetResponse的实现:

  在这里我还想介绍的就是req.AsyncGetResponse,其实现思路在异步编程封装里经常使用,在Async CTP中也提供了类似的扩展类库。AsyncGetRes上海徐汇企业网站制作ponse方法是一个WebRequest的扩展方法,在内部调用Async.FromBeginEnd封装WebRequest的BeginGetResponse和EndGetResponse。其大概想法就是这样的:


//以下都不是真实代码,仅为了阐明思路
 publicstatic Async AsyncGetResponse(this WebRequest request)
 {
  return Async.FromBeginEnd(request.BeginGetResponse,request.EndGetResponse,request);
 }
//下面是Async类的FromBeginEnd方法伪代码
 publicstatic Async FromBeginEnd(Func beginAction,Func endAction,WebRequest request)
 {
//创建一个async,类似一个工作项或Task
  Async async
= ...
  IAsyncResult ar
= null;
  AsyncCallback callback
= (state) =
  {
  WebResponse response
= endAc上海网站建设tion(ar);
//当给async这个任务设定了结果后就表明该任务执行完毕了,它以后的任务可以接着执行了
  上海企业网站设计与制作async.Result
= response;
  };
  ar
= beginAction(callback,request);
  return async;
  }

  我们可以将Async所代表的东西当作一个可以在未来某个时刻获得结果的任务,它现在还在执行。等到它的Result被设置的时候该任务就会完成,完成后就会触发一个事件,我们要做的就是注册这个事件,然后在事件发生后我们接着执行req.AsyncGetResponse的代码(如何实现是工作流的功劳)。

  F#中还提供了对其他异步方法的扩展,思路跟这里差不多,都可以使用AsyncXXX的方法调用。

  这里需要注意的是,因为Asynca仅仅表示一个未来可获得结果的任务,所以它内部不一定必须包含异步的操作。我们甚至可以将一段计算密集型的代码放到它内部(比如解一个方程),它就仅仅提供了一个调度的单元,更好的组织我们的代码。比如下面这样的代码:


Async.Parallel [ async{//长时间运行的任务1}; async{//长时间运行的任务2}....]

  我们利用async{}创建很多运算单元,然后利用Async.Parallel方法并行的执行这些计算单元。这样的代码比零散执行的代码更容易读,就像创建了很多对象来表示这些计算单元一样。

  总结:

  本文只是简单的介绍了下F#中编写异步编程的方法。我希望读者看完本文后能建立这样一些概念:

  1、上面代码中async{}内的代码是异步执行的,没有线程被阻塞,即使是访问非常慢的远程服务器时。

  2、async返回的Asynca代表一个未来可以得到结果 a 的任务。

  3、利用这种FromBeginEnd封装传统的异步编程的BeginXXX和EndXXX方法的方式是提供异步扩展库的常用做法。

时间: 2024-09-23 23:00:48

.NET中的“.NET研究”异步编程:使用F#简化异步编程的相关文章

.NET中的异步编程“.NET技术”:使用F#简化异步编程

不管是使用yield或借助第三方类库来简化异步编程,或多或少总是感觉不那么正统,有点hack的感觉.这种感觉在实验阶段倒还可以,要是用在产品中总有点担心,即使这些类库来自权威的第三方,我不知道大家有没有跟我同样的感觉.那么这个时候我们就会想,如果在语言中直接能提供这种机制该多好呢. F#的异步工作流 在Visual Studio 2010中,新包含了一种语言:F#.F#的一大特性就是异步计算.能让你用同步的方式编写异步的代码,不用使用AsyncCallback回调将一个方法分为两段,也不用注册异

微软缘何“.NET研究”认为VB与C#需要异步语法

在过去几年间,多线程编程已经成为了一个热门话题.虽然我们长久以来一直都希望能有高速响应的用户界面,但实现这个愿望的工具却迟迟不见踪迹.对于大多数框架(包括.NET程序员所使用的那些框架)来说,对用户界面的更新仍然局限于单独一个线程,同时,硬件制造商已经转向了多核来代替更快的CPU. C#与VB一开始提供了非常简单的并发支持,这是通过对监视器与委托使用lock/SyncLock关键字来实现的,异步程序库通过这两个关键字实现异步编程.在随后的几个版本中,我们并没有看到这两种语言在异步领域有任何进展,

Android中加载网络资源时的优化缓存和异步机制

网上关于这个方面的文章也不少,基本的思路是线程+缓存来解决.下面提出一些优化: 1.采用线程池 2.内存缓存+文件缓存 3.内存缓存中网上很多是采用SoftReference来防止堆溢出,这儿严格限制只能使用最大JVM内存的1/4 4.对下载的图片进行按比例缩放,以减少内存的消耗 具体的代码里面说明.先放上内存缓存类的代码MemoryCache.java: public class MemoryCache { private static final String TAG = "MemoryCa

GWT例子中的分页研究.

GWT demo中的分页研究.   Mail 类是主要的模块.    private MailList mailList; 是分页所需要的主要的类.   public class MailList extends Composite implements ClickHandler {     MailList下面有一个 private FlexTable table = new FlexTable (); 是用来动态显示分页数据的类.   private HorizontalPanel navB

VB编程 及EXCEL 的VBA编程,用什么把一段代码括起来啊(就是用什么东西来实现C语言中的{}功能啊)?

问题描述 VB编程及EXCEL的VBA编程,用什么把一段代码括起来啊(就是用什么东西来实现C语言中的{}功能啊)? 解决方案 解决方案二:不是有begin和end吗解决方案三:region?C的{}有很多啊,只能你VB书都没看过if...endif-------------if{}for...endfor---------for{}解决方案四:for..next.............我草解决方案五:学c的时候用按键精灵的时候我也愣了一阵子...很多是用end,if之后用endif,while

物联网在智慧城市建设中的角色研究

随着现代通信技术.物联网技术的不断发展.物联网的发展成为智慧城市发展的催化剂,本文以济南市智慧城市发展为例,在智慧城市发展现状的基础上,对物联网在智慧城市建设中的角色进行研究,以期为物联网在智慧城市发展中起到更好的作用提供理论依据. 一.智慧城市发展现状 随着现代科技的飞速发展,智慧城市已成为全球城市发展的战略首择.目前国内外智慧城市的发展建设处于发展探索阶段,但是不同的城市在发展智慧城市的时候侧重点各有不同.新加坡主要侧重交通.教育和医疗系统的应用,意在建设一个市民.企业.政府三者合作的电子系

JSP中操作数据库的常用SQL标签用法总结_JSP编程

<sql:setDataSource>标签设定数据源 语法结构: 复制代码 代码如下:     <sql:setDataSource url="jdbcUrl" driver="driverClassName" user="userName" password="password" [var = "varName"][scope="{page | request | sessio

MEF——.NET中值“.NET研究”得体验的精妙设计

MEF(Managed Extensibility Framework)是.NET Framework 4.0一个重要的库,Visual Studio 2010 Code Editor的扩展支持也是基于MEF构建的.MEF的目标是简化创建可扩展的应用程序,其核心类是ComposablePart,即具有组合能力的组件,每一个称为ComposablePart(中文可为可组合构件,不过下文一直采用英文来表示,这样比较贴切)的组件可以组合(称为Import)其它组件的功能(其它组件通过声明Export提

Spring中WebApplicationContext的研究

Spring中WebApplicationContext的研究 ApplicationContext是Spring的核 心,Context我们通常解释为上下文环境,我想用"容器"来表述它更容易理解一些,ApplicationContext则是"应用的容器" 了:P,Spring把Bean放在这个容器中,在需要的时候,用getBean方法取出,虽然我没有看过这一部分的源代码,但我想它应该是一个类似 Map的结构.在Web应用中,我们会用到WebApplicationC