zoukankan      html  css  js  c++  java
  • C#中的异步多线程3 await和异步控制流

    异步方法的结构包含有3个不同的区域:

    async Task<int> CountCharactersAsync(int id,string site)
    {
        //section 1 第一个await表达式之前的部分
        Console.WriteLine("Starting CounCharacters");
        WebClient wc=new WebClient();
        //section 2 await表达式
        string result=await wc.DownloadStringTaskAsync(new Uri(site));
        //section 3 后续部分
        Console.WriteLine("CountCharacters Completed");
        return result.Length;
    }

    section 1:从方法开头到第一个await表达式之前的所有代码,这一部分应只包含少量且无需长时间处理的代码。

    section 2:await表达式,表示将被异步执行的任务。

    section 3:后续部分,await表达式之后出现的方法中的其余代码。包括其执行环节,所在线程信息,目前作用域内的变量值,以及当await表达式完成后要重新执行所需的其他信息。

    一、异步方法控制流

           一个异步方法的控制流,从第一个await表达式之前的代码开始,同步执行,直到遇到第一个await。这一区域实际上在第一个await表达式处结束,此时await任务还没有完成(一般没有完成)。当await任务完成时,方法将继续同步执行。如果还有其他await,就重复上述过程。(异步方法内部)

           当到达await表达式时,异步方法将控制返回到调用方法(跳出异步方法至调用方法)。如果方法的返回类型为Task或Task<T>类型,就讲创建一个Task对象,表示需异步完成的任务和后续,然后将该Task返回到调用方法。 

           异步方法内部:

           1、异步执行await表达式的空闲任务

           2、当await表达式完成时,执行后续部分。后续部分本身也可能包含其他await表达式,这些表达式也将按照相同方式处理,即异步执行await表达式,然后执行后续部分。

           3、当后续部分遇到return语句或到达方法末尾时,将:

                 3-1、如果方法返回类型为void,控制流退出

                 3-2、如果方法返回类型为Task,后续部分设置Task的属性并退出。如果返回类型为Task<T>,后续部分还将设置Task对象的Result属性。

           同时,调用方法中的代码将继续其进程,从异步方法获取Task对象。当需要实际值时,就引用Task对象的Result属性。届时,如果异步方法设置了该属性,调用方法就能获得该值并继续。否则,将暂停并等待该属性被设置,然后再继续执行。

            具体的各种控制流

            1、调用方法调用异步方法——同步执行代码,没有await表达式-返回调用方法继续执行

            2、调用方法调用异步方法——同步执行代码,有await表达式——await表达式任务没有完成——创建空闲任务,创建后续部分,返回到调用方法——A、返回到调用方法的部分会继续执行。B、异步方法会执行await的空闲任务——执行后续部分——设置返回的Task状态和返回值——退出

            3、调用方法调用异步方法——同步执行代码,有await表达式——await表达式任务完成——同步执行代码,有await表达式.

            注意:同步方法第一次遇到await时,所返回的对象类型并非await表达式的返回类型,而是同步方法头中的返回类型,它与await表达式的返回值类型没有任何关系。

            例如:  

    private async Task<int> CountCharactersAsync(string site)
    {
       WebClient wc=new WebClient();
       string result=await wc.DownloadStringTaskAsync(new Uri(site));
       return result.Length;
    }

             同步方法第一次遇到await表达式时所返回的对象其实是Task<int>,而并不是await表达式的string。Task<int>是异步方法的返回类型。而实际上return语句“返回”一个结果或到达异步方法结尾时,它并没有返回真正的某个值,而只是单纯的退出了。

    二、await表达式

            await表达式指定了一个异步执行的任务。其语法由await关键字和一个空闲对象/任务(Task)组成。这个任务可能是一个Task类型的对象,也可能不是。默认情况下,这个任务在当前线程异步执行。

            一个空闲对象/任务即是一个awaitable类型的实例。awaitable类型是指包含GetAwaiter方法的类型,该方法没有参数,返回一个awaiter类型的对象。awaiter类型包括以下成员:

           1、bool IsCompleted{get;}

           2、void OnCompleted(Action);

           3、void GetResult();或T GetResult();

           大部分时候,不需要构建自己的awaitable,而应该使用Task类,它是awaitable类型。.Net 4.5 BCL中有很多异步方法,返回Task<T>类型对象。将这些放至await表达式中,它们会在当前线程中异步执行。

           当有需要时如何编写自己的Task<T>类型方法?

           最简单的办法是使用Task.Run创建一个Task,其原型如下:Task Run(Func<TReturn> func)

           要将自己的方法传递给Task.Run方法,要注意的是Task.Run是在不同的线程上运行方法,需要基于该方法创建一个委托。3种不同写法:

        class MyClass
        {
            public int Get10()
            {
                return 10;
            }
            public async Task DoWorkAsync()
            {
                //Func委托,最后一个参数是返回类型,可以有0-16个其他参数
                Func<int> ten = Get10;
                int a = await Task.Run(ten);
                int b = await Task.Run(new Func<int>(Get10));
                int c = await Task.Run(() => { return 10; });
                Console.WriteLine("{0} {1} {2}", a, b, c);
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Task t = (new MyClass()).DoWorkAsync();
                t.Wait();
                Console.ReadLine();
            }
        }

    上面的例子中,Task.Run的签名是以Func<TResult>为参数。其他的重载还包括:

    Task.Run(Action action)

    Task.Run(Action action,CancellationToken token)

    Task<TResult>.Run(Func<TResult> function)

    Task<TResult>.Run(Func<TResult> function,CancellationToken token)

    Task.Run(Func<Task> function)

    Task.Run(Func<Task> function,CancellationToken token)

    Task<TResult>.Run(Func<Task<TResult>> function)

    Task<TResult>.Run(Func<Task<TResult>> function,CancellationToken token)

    当遇到特殊的方法不符合时,可以使用接收的Func委托的形式创建一个Lambda函数,这个函数只用于运行特殊方法。例如:Task.Run(()=>GetSum(4,5));

  • 相关阅读:
    [ffmpeg 扩展第三方库编译系列] 关于 mingw32 下编译libcaca
    新版本的tlplayer for android ,TigerLeapMC for windows发布了
    tlplayer 所有平台版本支持水印叠加
    更新Windows ActiveX,Ios
    Linux批量“解压”JAR文件
    Linux进阶路线
    30个实用的Linux find命令示例
    Redhat 无线(Wifi)上网命令行配置
    PLSQL developer常用技巧
    Hibernate4.3.5搭建Log4j日志环境
  • 原文地址:https://www.cnblogs.com/NicolasLiaoran/p/12936369.html
Copyright © 2011-2022 走看看