zoukankan      html  css  js  c++  java
  • WinRT中的异步操作

    在.net framework 4.5 中,所有异步操作的系统函数返回值为一般都是Task 或Task<TResult> ,但在WinRT中,所有的系统函数异步操作都源自于一个接口IAsyncInfo,

        public interface IAsyncInfo
        {
            Exception ErrorCode { get; }
            uint Id { get; }
            AsyncStatus Status { get; }
            void Cancel();
            void Close();
        }

    从这个接口上来看,它提供了取消和关闭任务的功能,并且能查看异步操作的执行状态,除了Status函数外,其它几个接口和TAP模式下的异步操作并没有直接关系,并且缺少await所需的GetResult()和OnCompleted()接口或能实现其功能的等价接口。也就是说,这个接口是不支持await的,对IAsyncInfo调用await会报编译错误。

    虽然IAsyncInfo接口并本身不支持异步功能,实际上实际上我们使用的是它的四个子类,他们提供了GetResult()和OnCompleted()接口的等价声明:

        public interface IAsyncAction : IAsyncInfo
        {
            AsyncActionCompletedHandler Completed { get; set; }
            void GetResults();
        }

        public interface IAsyncOperation<TResult> : IAsyncInfo
        {
            AsyncOperationCompletedHandler<TResult> Completed { get; set; }
            TResult GetResults();
        }

        public interface IAsyncActionWithProgress<TProgress> : IAsyncInfo
        {
            AsyncActionWithProgressCompletedHandler<TProgress> Completed { get; set; }
            AsyncActionProgressHandler<TProgress> Progress { get; set; }
            void GetResults();
        }

        public interface IAsyncOperationWithProgress<TResult, TProgress> : IAsyncInfo
        {
            AsyncOperationWithProgressCompletedHandler<TResult, TProgress> Completed { get; set; }
            AsyncOperationProgressHandler<TResult, TProgress> Progress { get; set; }
            TResult GetResults();
        }

    从它们的声明来看,IAsyncAction等价于不带返回值的异步任务Task,IAsyncOperation<TResult>等价带返回值的异步任务Task<T>。另外,还提供了两个带进度报告的版本:IAsyncActionWithProgress和IAsyncOperationWithProgress。

    虽然这四个接口本身都没有声明GetAwaiter(),但WinRT类库WindowsRuntimeSystemExtensions中定义了相应的GetAwaiter扩展函数,因此它们是支持await操作的,返回值从其接口GetResults()中获取。

        public static class WindowsRuntimeSystemExtensions
        {
            public static TaskAwaiter GetAwaiter(this IAsyncAction source);
            public static TaskAwaiter<TResult> GetAwaiter<TResult>(this IAsyncOperation<TResult> source);
            public static TaskAwaiter GetAwaiter<TProgress>(this IAsyncActionWithProgress<TProgress> source);
            public static TaskAwaiter<TResult> GetAwaiter<TResult, TProgress>(this IAsyncOperationWithProgress<TResult, TProgress> source);
        }

    在使用await操作时,我们往往还需要通过async关键字来配套使用,将多个await操作来重新封装成一个新的异步函数。在.net 4.5中,我们往往这么使用:

        public async Task AsyncOperation()
        {
            await ...
            return;
        }

    由于WinRT的异步返回值是IAsyncInfo,那么我们是不是该把Task换成等价的IAsyncOperation呢?

        public async IAsyncAction AsyncOperation()
        {
            await ...
            return;
        }

    实际上,当我们这么写时,会得倒一个"异步方法的返回类型必须为 void、Task 或 Task<T>"的编译错误。也就是说,在WinRT中,异步操作模型和.Net 4.5是一致的,本身还是基于Task的异步编程。

    既然Task仍然是WinRT的异步编程的一等公民,那为什么还要提供一个IAsyncInfo呢?让我们再回头看看IAsyncInfo接口,发现他具有Task所不支持的两个接口:Cancel和Close。

    • 对于Close函数的功能,MSDN中语焉不详,没看到明确说要在什么地方用和注意的地方。但有一点值得一提的是:在.Net 4.5的IO操作中,虽然读写提供了异步接口,但Open却是同步的,但WinRT中的Open也是异步的,通过IAsyncInfo.Close函数可以直接关闭异步打开的资源。但这个并非一定要提供一个Close接口不可,返回的TResult对象里一般也提供了Close接口,大可以用它来关闭资源。
    • 对于Cancel函数,这个功能是Task无法直接实现的,必须和CancellationTokenSource配合使用,而IAsyncInfo本身就提供了这个功能。

    从上可以看出:IAsyncInfo(的四个子接口)其实是个Task的增强版(支持Cancel和Close),WinRT系统的异步函数返回值提供的功能更加强大。

    既然IAsyncInfo比Task更加强大,其自然也是可以转换成Task的,在WindowsRuntimeSystemExtensions类中就提供了扩展函数AsTask()实现把IAsyncInfo(的四个子类)转换为Task,从而使用Task的各个功能函数,使之更加强大,例如:

    • 实现GetAwaiter()扩展函数,使得IAsyncAction系列接口支持await操作(这个是前面提及的系统已经实现了的)。

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

    • 支持异步操作后不返回UI线程

          await SomeMethodAsync().AsTask().ConfigureAwait(false);

    • 任务取消

            CancellationToken token = ...;
            await SomeMethodAsync().AsTask(token);

    • 进度报告

            IProgress<TProgress> progress = ...;
            await SomeMethodAsync().AsTask(progress);

    • 其它Task函数的接口

            Task firstCompleted = await Task.WhenAny(
                SomeMethod1Async().AsTask(),
                SomeMethod2Async().AsTask(),
                SomeMethod3Async().AsTask());

    既然知道了如何使用IAsyncInfo,除了系统自带的函数,我们如何创建自己的IAsyncInfo呢?常用方法有如下两种:

    1. 通过AsyncInfo.Run运算密集型的同步函数封装为返回值为IAsyncInfo的异步函数,这个非常类似于Task.Run
    2. 通过扩展方法AsAsyncAction 和 AsAsyncOperation 将Task转换为相应的IAsyncInfo,这个主要用于封装async关键字生产返回值为Task的异步函数。

    以上只是对WinRT的异步操作进行了一个简单的介绍,如果想更加详细的了解相关知识,请参考MSDN文章:深入探究 WinRT 和 await将 .NET 任务作为 WinRT 异步操作公开

     

  • 相关阅读:
    Android 性能优化 四 布局优化merge标签的使用
    一种Android换肤机制的实现
    java提高篇(十)-----详解匿名内部类 ,形参为什么要用final
    Android源码之Matrix
    android 沉浸式状态栏
    [置顶]关于java中根据身份证求生日和年龄的问题
    将博客搬至CSDN
    android——fragment长时间home或者锁屏java.lang.IllegalArgumentException:No view found for id for....
    百度搜索附近加盟店等基于LBS云搜索功能的实现
    android——拍照,相册图片剪切其实就这么简单
  • 原文地址:https://www.cnblogs.com/TianFang/p/2662975.html
Copyright © 2011-2022 走看看