技术开发 频道

.NET中的异步编程:使用F#简化异步编程

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

  req.AsyncGetResponse的实现:

  在这里我还想介绍的就是req.AsyncGetResponse,其实现思路在异步编程封装里经常使用,在Async CTP中也提供了类似的扩展类库。AsyncGetResponse方法是一个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
= endAction(ar);

  
//当给async这个任务设定了结果后就表明该任务执行完毕了,它以后的任务可以接着执行了

  async.Result
= response;

  };

  ar
= beginAction(callback,request);

  return async;

  }

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

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

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

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

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

  总结:

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

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

  2、async返回的Async<’a>代表一个未来可以得到结果 ‘a 的任务。

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

  下一篇文章我们会看看F#中工作流是如何工作的,然后会再次回到本文看看async{}背后到底隐藏了些什么。

0
相关文章