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 异步操作公开

     

  • 相关阅读:
    1026 Table Tennis (30)
    1029 Median
    1025 PAT Ranking (25)
    1017 Queueing at Bank (25)
    1014 Waiting in Line (30)
    1057 Stack (30)
    1010 Radix (25)
    1008 Elevator (20)
    字母大小写转换
    Nmap的基础知识
  • 原文地址:https://www.cnblogs.com/TianFang/p/2662975.html
Copyright © 2011-2022 走看看