zoukankan      html  css  js  c++  java
  • C# 异步编程(async和await)

    1. 源起

    在我们从 .Net 转 .Net Core 的过程中,我们通常会查看一些源码或者看书进行学习,在其中你可能会看到类似于这样的代码

     1 // 1. Asp.Net Core 的 控制器 类
     2 [HttpGet]
     3 public async Task<IActionResult> Index()
     4 {
     5      ......
     6      await ......
     7      ......
     8 }
     9 
    10 // 2. Console 的 Program.cs 文件
    11 static async Task Main(string[] args)
    12 {
    13      ......
    14      await ......
    15      ......
    16 }

    这是一个很重要的 “新特性”---异步编程。在 C# 里面异步编程是通过关键字 async 和 await 两个关键字实现的。

    那什么是异步编程?async、await是怎么样实现异步编程的呢?

    2. 为什么要异步编程

    在介绍异步编程之前,我们先说一下同步编程。

    通常我们编写的代码在被执行时,通常是自上而下一行一行的执行,如过是执行方法,则进入方法内部继续一行一行执行。

    这就是同步执行,也称之为同步编程(也可以说是编程)。

    你会发现同步编程有一个问题,就是但是当一个方法执行耗时比较长时(例如读取文件内容),会阻塞下面的代码执行,整个软件都会进入等待状态(如是GUI界面,则执行操作的线程会阻塞,整个操作界面也会处于等待状态),体验度相当的不好---尤其是在计算机有多核的情况下,完全可以在另一个CPU上干其他的工作,同时计算机完成耗时任务的时候通知你。这就是异步编程的起源更多示例

    3. C# 异步编程

    通过使用异步编程,你可以避免性能瓶颈并增强应用程序的总体响应能力。 但是,编写异步应用程序的传统技术可能比较复杂,使它们难以编写、调试和维护。

    虽然 .Net 中有几种异步编程模式,但是目前建议使用的只有一种(TAP),我们将对历史有一些简单的说明,对于EAP进行更深入的介绍。

    3.1 .Net 提供了3中异步编程模型(更多介绍

    • TAP(基于任务的异步模式):使用单一方法表示异步操作的开始和结束,是.Net中进行异步编程的推荐方法。(.Net Framework 4中引入的)
    • EAP(基于事件的异步模式):提供异步行为的基于事件的旧模型。 这种模式需要后缀为 Async 的方法,以及一个或多个事件、事件处理程序委托类型和 EventArg 派生类型。 EAP 是在 .NET Framework 2.0 中引入的。 不建议新的开发使用此模式。
    • APM(异步编程模型):(也称为 IAsyncResult 模式),这是使用 IAsyncResult 接口提供异步行为的旧模型。 在这种模式下,同步操作需要 Begin 和 End 方法(例如,BeginWrite 和 EndWrite以实现异步写入操作)。 不建议新的开发使用此模式。

    3.2 TAP(基于任务的异步模式)

    C# 拥有语言级别的异步编程模型,它遵循基于任务的异步模式。

    C# 异步编程的核心是 Task 和 Task<T> 对象(深入了解Task和Task<T>),这两个对象对异步操作建模。它们受关键字 async 和 await 的支持(二者是异步编程的核心关键字)。通过这两个关键字,可以使用 .NET Framework、.NET Core 或 Windows 运行时中的资源,轻松创建异步方法(几乎与创建同步方法一样轻松)。 使用 async 关键字定义的异步方法简称为“异步方法”。await 关键字控制执行 await 的方法的调用方,且它最终允许 UI 具有响应性或服务具有灵活性。

    4. 异步编程 示例

      1 using System;
      2 using System.Threading;
      3 using System.Threading.Tasks;
      4 
      5 namespace ConsoleApp
      6 {
      7     class Program
      8     {
      9         static async Task Main(string[] args)
     10         {
     11             try
     12             {
     13                 //线程池,最大和最小数量(CompletionPortThreads 异步I/O线程数量)
     14                 //相关资料:https://docs.microsoft.com/zh-cn/dotnet/standard/threading/the-managed-thread-pool
     15                 ThreadPool.GetMinThreads(out int minWorkerThreads, out int minCompletionPortThreads);       //6 6
     16                 ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);       //32767 1000
     17 
     18                 ShowMsg(minWorkerThreads.ToString());
     19                 ShowMsg(minCompletionPortThreads.ToString());
     20                 ShowMsg(maxWorkerThreads.ToString());
     21                 ShowMsg(maxCompletionPortThreads.ToString());
     22 
     23                 #region 【1. 使用示例】
     24                 ////测试async和await(运行在ThreadPool)
     25                 ////相关资料:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model
     26                 //ShowMsg($"【Main start 1】");
     27                 //Test1Async();        //异步执行,但是不知道什么时候执行
     28                 //Test11Async();       //异步执行,但是不知道什么时候执行
     29                 //ShowMsg($"【Main end 1】");
     30                 //ShowMsg($"【Main start 2】");
     31                 //await Test2Async();  //同步执行,等待任务执行完成
     32                 //ShowMsg($"【Main end 2】");
     33 
     34                 //ShowMsg($"【Main start 3】");
     35                 //Task<String> task = Test3Async();    //有返回值的方法,异步执行,但是不知道什么时候执行
     36                 //ShowMsg($"【Main end Task】");
     37                 //ShowMsg($"{task.Result}");        //等待异步操作执行完成之后,获取执行结果(相当于await)
     38 
     39                 //ShowMsg($"【Main end 3】");
     40 
     41                 //TaskRun();
     42 
     43                 //ShowMsg($"【Used samples end】");
     44 
     45                 #endregion
     46 
     47                 #region 【2. 错误捕获示例】
     48                 ////相关资料:https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/try-catch#async-method-example
     49                 //// sample 1
     50                 //await Exception1Async();
     51 
     52                 //// sample 2
     53                 //Task<String> exceptionSample1 = Exception1Async();
     54                 //exceptionSample1.Wait();
     55 
     56                 //// sample 3
     57                 //Console.WriteLine(exceptionSample1.Result);
     58 
     59                 //// sample 4
     60                 //Exception1Async();
     61 
     62                 // 结论:
     63                 //     以上四种示例,前三种会进入外层try-catch,第四种则不会(因为是异步执行,不需要等待回传结果,需要自行处理报错信息)
     64 
     65                 //if (null != exceptionSample1.Exception)
     66                 //{
     67                 //}
     68                 #endregion
     69 
     70             }
     71             catch (Exception ex)
     72             {
     73                 Console.WriteLine(ex);
     74             }
     75 
     76             ShowMsg("The End!");
     77         }
     78 
     79         static async Task Test1Async()
     80         {
     81             ShowMsg($"Test start 1");
     82             await Task.Delay(300);
     83             ShowMsg($"Test end 1");
     84         }
     85 
     86         static async Task Test11Async()
     87         {
     88             ShowMsg($"Test start 1111");
     89             await Task.Delay(300);
     90             ShowMsg($"Test end 1111");
     91         }
     92 
     93         static async Task Test2Async()
     94         {
     95             ShowMsg($"Test start 2");
     96             await Task.Delay(300);
     97             ShowMsg($"Test end 2");
     98         }
     99 
    100         static async Task<String> Test3Async()
    101         {
    102             ShowMsg($"Test start 3");
    103             await Task.Delay(300);
    104             ShowMsg($"Test end 3");
    105             return "123";
    106         }
    107 
    108         static void ShowMsg(String msg)
    109         {
    110             Console.WriteLine($" Time:{ DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fffff") } . Message: {msg}");
    111         }
    112 
    113         static async Task<String> Exception1Async()
    114         {
    115             await Task.Delay(100);
    116 
    117             // Uncomment each of the following lines to
    118             // demonstrate exception handling.
    119 
    120             throw new OperationCanceledException("canceled");
    121             throw new Exception("Something happened.");
    122             return "Done";
    123         }
    124 
    125         static async Task TaskRun()
    126         {
    127             await Task.Run(() =>
    128             {
    129                 Thread.Sleep(100);
    130                 ShowMsg("This is task run method.");
    131             });
    132         }
    133 
    134     }
    135 }

    附录

    异步编程

    https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Asynchronous/Concepts

    异步编程模式

    https://docs.microsoft.com/zh-cn/dotnet/standard/asynchronous-programming-patterns/


    C# 异步编程
    https://docs.microsoft.com/zh-cn/dotnet/csharp/async

    使用 Async 和 Await 的异步编程
    https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/

    异步编程模型
    https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model

    try-catch(C# 参考)
    https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/try-catch

    托管线程池
    https://docs.microsoft.com/zh-cn/dotnet/standard/threading/the-managed-thread-pool

    深入了解异步
    https://docs.microsoft.com/zh-cn/dotnet/standard/async-in-depth

    基于任务的异步模式
    https://docs.microsoft.com/zh-cn/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap

    任务并行库

    https://docs.microsoft.com/zh-cn/dotnet/standard/parallel-programming/task-parallel-library-tpl

  • 相关阅读:
    波形相加
    2003-2011电赛题目
    个人课程总结
    程序员的修炼之道:从小工到专家阅读笔记03
    程序员修炼之道:从小工到专家阅读笔记02
    计算最长英语单词链
    学习进度十五
    程序员修炼之道:从小工到专家阅读笔记01
    学习进度十四
    用户体验评价
  • 原文地址:https://www.cnblogs.com/zhizihuakai/p/15026047.html
Copyright © 2011-2022 走看看