• C# 异步编程(async&await)


    什么是异步编程

    每次启动程序时,系统会自动在内存中创建一个进程。进程是构成运行程序的资源的集合。这些资源包括虚地址空间、文件句柄和许多其他程序运行所需的资源。
    在进程的内部,系统会创建一个称为线程的内核(Kerne )的对象,它代表了真正的运行程序。线程是执行线程的简称。当进程建立,系统就会由主程序的Main方法的第一行语句处开始了线程的执行。

    • 在默认情况下,一个进程只包含一个线程,即从程序的开始,一直执行到结束。
    • 其实线程是可以派生其他线程,在任意时刻,一个进程都可以包含不同状态的多个线程,来执行程序的不同部分。
    • 如果一个进程拥有一个线程,它们将共享进程的资源。
    • 系统为处理器规划的执行单元,是线程而非进程。

    在很多时候,我们在进程中使用单一线程从头到尾地执行程序,这种简单模式会导致性能和用户体验另人难以接受。
    比如程序向另外一台服务器发出请求,由于网络等外部原因,此种通信任务往往会耗费大量时间,进程如果在此期间仅仅只能等待网络或网络上其他机器的响应,将严重地降低了性能。程序不应该浪费等待的时间,而应该更加高效地利用,在等待的时间执行其他任务,回复到达后在继续执行第一个任务。
    如果程序调用某个方法,等待其执行全部处理后才能继续执行,我们称其为同步的。相反,在处理完成之前就返回调用方法则是异步的。
    我们在编程语言的流程中添加了异步控制的部分,这部分的编程可以称之为异步编程

    总结:

    同步~同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去

    异步~异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
         异步是一种目的。手段有 异步委托、多线程、线程池等...

    .NET异步编程的发展历程

    异步编程四个发展过程,参考:[你必须知道的异步编程]

    NET1.1 APM(异步编程模型):.net 1.0时期就提出的一种异步模式,基于IAsyncResult接口实现BeginXXX和EndXXX类似的方法。HttpWebRequest就实现了该模式(继承IAsyncResult接口并且实现BeginXXX和EndXXX方法)

    NET2.0 EAP(基于事件的异步编程模型):实现了基于事件的异步模式的类将具有一个或者多个以Async为后缀的方法和对应的Completed事件,并且这些类都支持异步方法的取消、进度报告和报告结果。然而.net中并不是所有的类都支持EAP。当调用基于事件的EAP模式的类的XXXAsync方法时,就开始了一个异步操作,并且基于事件的EAP模式是基于APM模式之上的,而APM又是建立在委托之上的。

    NET4.0 TAP(基于任务的异步编程模型):.net 4.0为我们带来了Task的异步,我们有以下4种方法创建Task:

    1,Task.Factory.StartNew(),比较常用。

    2,Task t1 = new Task(() => { Console.WriteLine("t1 start"); });    t1.Start();

    3,Task.Run(),是.net 4.5中增加的。

    4,Task.FromResult(),如果结果是已计算,就可以使用这种方法来创建任务。

    NET4.5 异步和等待(async和await)

    但它们的本质都是使用线程池和委托机制的。

    async/await模式之基本操作

    在语法上,异步方法具有如下的特点:

    • 方法头中包含async方法修饰符。
    • 包含一个或多个await表达式,表示可以异步完成的任务。
    • 必须具备以下三种返回类型:
      • void
      • Task
      • Task<T>
    • 异步方法的参数可以为任意类型任意数量,但不能为out和ref参数。
    • 安装预定,异步方法的名称应该以Async为后缀。
    • 除了方法以外,Lambda表达式和匿名方法也可以作为异步对象。

    异步方法的返回类型

    • Task<T>:如果调用方法要从调用中获取一个T类型的值,异步方法的返回值就必须是Task<T>。调用方法将通过读取Task的Result属性来获取这个T类型的值
    Task<int> value = DoStuff.CalculateSumAsync(5, 6);
    ...
    Console.WriteLine( “Value: {0}”, value.Result);

    任何返回Task<T>类型的异步方法其返回值必须为T类型或可以隐式转换为T的类型。

    • Task:如果调用方法不需要从异步方法在返回值,但需要坚持异步方法的状态,那么异步方法可以返回一个Task类型的对象。这时,即使异步方法中出现return语句,也将不会返回任何东西
    • void:如果调用方法仅仅想执行异步方法,而不需要与它做进一步的交互时【这称为“调用并遗忘”(fire and forget)】,异步方法可以返回void类型。这时与上一种情况类似,即使异步方法中包含任何return语句,也不会返回任何东西。

    学习参考:

    1、探索c#之Async、Await剖析

    使用Async标记Test为异步方法,用Await标记的方法 一般是需要耗时的操作。主线程碰到await时会立即返回,继续以非阻塞形式执行主线程下面的逻辑。当await耗时操作完成时,继续执行await后面的逻辑:

     Test();
            Console.WriteLine("A逻辑");
            static async void Test()
            {
                await Task.Run(() => { Thread.Sleep(1000); Console.WriteLine("B逻辑"); });
                Console.WriteLine("C逻辑"); 
            }

    Async、Await的加入让原先这种混乱的步骤,重新拨正了,执行步骤是:A逻辑->B逻辑->C逻辑。

    主线程调用Test(),await可能会开辟一个Task任务线程。

    注意:这3个步骤是有可能会使用同一个线程的,也可能会使用2个,甚至3个线程。 可以用Thread.CurrentThread.ManagedThreadId测试下得知。

    关于async和await常问的问题

    问题一:是不是写了async关键字的方法就代表该方法是异步方法,不会堵塞线程呢?

      答: 不是的,对于只标识async关键字的(指在方法内没有出现await关键字)的方法,调用线程会把该方法当成同步方法一样执行,所以然而会堵塞GUI线程,只有当async和await关键字同时出现,该方法才被转换为异步方法处理。

    问题二:“async”关键字会导致调用方法用线程池线程运行吗?

      答: 不会。被async关键字标识的方法不会影响方法是同步还是异步运行并完成,而是,它使方法可被分割成多个片段,其中一些片段可能异步运行,这样这个方法可能异步完成。这些片段界限就出现在方法内部显示使用”await”关键字的位置处。所以,如果在标记了”async”的方法中没有显示使用”await”,那么该方法只有一个片段,并且将以同步方式运行并完成。在await关键字出现的前面部分代码和后面部分代码都是同步执行的(即在调用线程上执行的,也就是GUI线程,所以不存在跨线程访问控件的问题),await关键处的代码片段是在线程池线程上执行。总结为——使用async和await关键字实现的异步方法,此时的异步方法被分成了多个代码片段去执行的,而不是像之前的异步编程模型(APM)和EAP那样,使用线程池线程去执行一整个方法。

    其他学习 

    C#语法——await与async的正确打开方式

    async & await 的前世今生(Updated)

    关于async与await的FAQ

    C#中 Thread,Task,Async/Await,IAsyncResult 的那些事儿!

    异步编程系列

  • 相关阅读:
    form表单提交json格式数据
    docker搭建jenkins
    consul搭建服务注册和
    docker创建mysql镜像
    Swagger入门
    net coer log4+ELK搭建
    log4配置
    netcore autofac依赖注入
    netcore 跨域
    netcore 读取配置文件
  • 原文地址:https://www.cnblogs.com/peterYong/p/11371023.html
Copyright © 2020-2023  润新知