HTML5技术

C#与C++的发展历程第三 - C#5.0异步编程巅峰 - hystar(13)

字号+ 作者:H5之家 来源:博客园 2016-01-15 10:03 我要评论( )

将BeginXXX/EndXXX的APM模式代码转为async异步方法只需要利用TaskFactory类的FromAsync方法即可,我们以介绍APM时提到的HttpWebRequest为例: publicTaskWebResponseGetResponseAsync(WebRequestclient){returnTask

将BeginXXX/EndXXX的APM模式代码转为async异步方法只需要利用TaskFactory类的FromAsync方法即可,我们以介绍APM时提到的HttpWebRequest为例:

public Task<WebResponse> GetResponseAsync(WebRequest client) {     return Task<WebResponse>.Factory.FromAsync(client.BeginGetResponse, client.EndGetResponse, null); }

TaskFactory的FromAsync方法中使用TaskCompletionSource<T>来构造Task对象。

封装EAP模式的代码要比APM麻烦一些,我们需要手动构造TaskCompletionSource对象(代码来自,手打的)。

WebClient client; Uri address; var tcs = new TaskCompletionSource<string>(); DownloadStringCompletedEventHandler hander = null; handler = (_, e)=> {     client.DownloadStringCompleted -= handler;     if(e.Cancelled)         tcs.TrySetCanceled();     else if(e.Error != null)         tcs.TrySetException(e.Error);     else         tcs.TrySetResult(e.Result); } client.DownloadStringCompleted += handler; client.DownloadStringAsync(address); return tcs.Task;

可以看到TaskCompletionSource提供了一种手动指定Task结果来构造Task的方式。

 

上面写了那么多,真没有信息保证全部都是正确的。最后推荐3篇文章,相信它们对理解async异步方法会有很大帮助,本文的很多知识点也是来自这几篇文章:

  • Understanding C# async / await (1) Compilation

  • Understanding C# async / await (2) Awaitable-Awaiter Pattern

  • Understanding C# async / await (3) Runtime Context

  •  

    WinRT 异步编程 C#

    WinRT是完全不同于.NET的一种框架,目地就是把Windows的底层包装成API让各种语言都可以简单的调用。WinRT中对异步的实现也和.NET完全不同,这一小节先看一下WinRT中异步机制的实现方法,再来看一下怎样使用C#和.NET与WinRT中的异步API进行交互。

    前文提到async异步编程中两个比较重要的对象是awaitable和awaiter。在WinRT中充当awaitable的是IAsyncInfo接口的对象,具体使用中有如下4个实现IAsyncInfo接口的类型:

  • IAsyncAction

  • IAsyncActionWithProgress<TProgress>

  • IAsyncOperation<TResult>

  • IAsyncOperationWithProgress<TResult, TProgress>

  • 由泛型参数可以看出Action和Operation结尾的两个类型不同之处在于IAsyncAction的GetResults方法返回void,而IAsyncOperation<TResult>的GetResults方法返回一个对象。WithProgress结尾的类型在类似类型的基础上增加了进度报告功能(它们内部定义了Progress事件用来执行进度变更时的处理函数)。

    Task和IAsyncInfo分别是对.NET和WinRT中异步任务的包装。它们的原理相同但具体实现有所不同。IAsyncInfo表示的任务的状态(可以通过Status属性查询)有如下几种(和Task对照,整理自MSDN):

    Task状态

    (TaskStatus类型)

    IAsyncInfo状态

    (AsyncStatus类型)

    RanToCompletion

    Completed

    Faulted

    Error

    Canceled

    Canceled

    所有其他值和已请求的取消

    Canceled

    所有其他值和未请求的取消

    Started

    另外获取异常的方式也不一样,通过Task中的Exception属性可以直接得到.NET异常,而IAsynInfo中错误是通过ErrorCode属性公开的一个HResult类型的错误码。当时用下文价绍的方法将IAsynInfo转为Task时,HResult会被映射为.NET Exception。

    之前我们说这些IAsyncXXX类型是awaitable的,但为什么这些类型中没有GetAwaiter方法呢。真相是GetAwaiter被作为定义在.NET的程序集System.Runtime.WindowsRuntime.dll中的扩展方法,因为基本上来说async/awati还是C#使用的关键字,而C#主要以.NET为主。

    这些扩展方法声明形如(有多个重载,下面是其中2个):

    public static TaskAwaiter GetAwaiter<TResult>(this IAsyncAction source); public static TaskAwaiter<TResult> GetAwaiter<TResult, TProgress>(this IAsyncOperationWithProgress<TResult, TProgress> source);

    我们又见到了熟悉的TaskAwaiter。这个方法的实现其实也很简单(以第一个重载为例):

    public static TaskAwaiter GetAwaiter(this IAsyncAction source) {   return WindowsRuntimeSystemExtensions.AsTask(source).GetAwaiter(); }

    可以看到就是通过task.GetAwaiter得到的TaskAwaiter对象。

    这一系列扩展方法的背后又有一个更重要的扩展方法 - AsTask()。

    AsTask方法有更多的重载,其实现原理和前文介绍将EAP包装为async异步模式的代码差不多,都是通过TaskCompletionSource来手工构造Task。下面展示的是一个最复杂的重载的实现:

    public static Task<TResult> AsTask<TResult, TProgress>(     this IAsyncOperationWithProgress<TResult, TProgress> source,      CancellationToken cancellationToken,      IProgress<TProgress> progress) {   if (source == null)     throw new ArgumentNullException("source");   TaskToAsyncOperationWithProgressAdapter<TResult, TProgress> withProgressAdapter = source as TaskToAsyncOperationWithProgressAdapter<TResult, TProgress>;   if (withProgressAdapter != null && !withProgressAdapter.CompletedSynchronously)   {     Task<TResult> task = withProgressAdapter.Task as Task<TResult>;     if (!task.IsCompleted)     {       if (cancellationToken.CanBeCanceled && withProgressAdapter.CancelTokenSource != null)         WindowsRuntimeSystemExtensions.ConcatenateCancelTokens(cancellationToken, withProgressAdapter.CancelTokenSource, (Task) task);       if (progress != null)         WindowsRuntimeSystemExtensions.ConcatenateProgress<TResult, TProgress>(source, progress);     }     return task;   }   switch (source.Status)   {     case AsyncStatus.Completed:       return Task.FromResult<TResult>(source.GetResults());     case AsyncStatus.Canceled:       return Task.FromCancellation<TResult>(cancellationToken.IsCancellationRequested ? cancellationToken : new CancellationToken(true));     case AsyncStatus.Error:       return Task.FromException<TResult>(RestrictedErrorInfoHelper.AttachRestrictedErrorInfo(source.get_ErrorCode()));     default:       if (progress != null)         WindowsRuntimeSystemExtensions.ConcatenateProgress<TResult, TProgress>(source, progress);       AsyncInfoToTaskBridge<TResult, TProgress> infoToTaskBridge = new AsyncInfoToTaskBridge<TResult, TProgress>();       try       {         source.Completed = new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(infoToTaskBridge.CompleteFromAsyncOperationWithProgress);         infoToTaskBridge.RegisterForCancellation((IAsyncInfo) source, cancellationToken);       }       catch       {         if (Task.s_asyncDebuggingEnabled)           Task.RemoveFromActiveTasks(infoToTaskBridge.Task.Id);         throw;       }       return infoToTaskBridge.Task;   } }

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 2年前端学习历程,与找不到工作的悲愤与吐槽!(100%真实经历,看博主怎么一步步走向失业) - 蒋启钲

      2年前端学习历程,与找不到工作的悲愤与吐槽!(100%真实经历,看博

      2017-03-29 11:00

    • 开源第三方登录组件OAuthLogin2.0 支持QQ,阿里巴巴,淘宝,京东,蘑菇街,有赞等平台 - 大壮他哥

      开源第三方登录组件OAuthLogin2.0 支持QQ,阿里巴巴,淘宝,京东,蘑菇街

      2017-01-20 15:00

    • 从零到百亿互联网金融架构发展史 - 纯洁的微笑

      从零到百亿互联网金融架构发展史 - 纯洁的微笑

      2017-01-14 13:00

    • 记一次企业级爬虫系统升级改造(四):爬取微信公众号文章(通过搜狗与新榜等第三方平台) - 彩色铅笔

      记一次企业级爬虫系统升级改造(四):爬取微信公众号文章(通过搜狗

      2017-01-12 10:01

    网友点评