【.NET Core】深入理解async 和 await 理解

简介: 【.NET Core】深入理解async 和 await 理解

一、概述

async和await是C#5.0时代引入异步编程的核心关键字。通过使用异步编程,你可以避免性能瓶颈并增强程序响应能力。但是,编写异步应用程序的传统技术可能比较复杂,使异步编程难编写,调试和维护。


C#中的async和await关键字是异步编程的核心。通过这两个关键字,可以使用.NET Framework,.NET Core或Windows运行时中的资源,轻松创建异步方法。使用async关键字定义的异步方法简称为”异步方法“。


二、async异步执行机制理解

  • 在C#中,async标记了一个包含异步执行的函数,通过async的函数若在主线程中直接调用,则函数一开始扔在主线程中执行。
  • async标记的函数内部必须包含await标记需要异步执行的函数,若当前函数在主线程中直接调用,则await标记当前的代码在主线程中执行,await标记后的代码在其异步子线程中执行。
  • async标记的函数返回值必须为void、Task、Task<TResult>类型,可以理解为async标记的函数返回的是null,即将执行的任务、带返回结果的即将执行的任务。
  • async标记的函数可以继续往下调用async标记函数。

三、asyncawait应用

3.1 asyncawait简单应用

internal class Program
{
   static void Main(string[] args)
   {
        Method1();
        Method2();
        Console.ReadKey();
    }
    public static async Task Method1()
    {
        await Task.Run(() =>
        {
            for (int i = 0; i < 30; i++)
            {
                Task.Delay(100);
                Console.WriteLine(" Method 1");
            }
         });
    }
    public static void Method2()
    {
        for (int i = 0; i < 25; i++)
        {
              Task.Delay(80);
              Console.WriteLine(" Method 2");
         }
     }
}

从上面代码运行结果可以看出,Method1和Method2相互并没有依赖关系,Method1和Method2并不是在等待对方完成。

3.2 带有返回值asyncawait应用

static void Main(string[] args)
{
     callMethod();
     Console.ReadKey();
}
public static async void callMethod()
{
     Task<int> task = Method1();
     Method2();
     int count = await task;
     Method3(count);
}
public static async Task<int> Method1()
{
     int count = 0;
     await Task.Run(() =>
     {
          for (int i = 0; i < 20; i++)
          {
              Console.WriteLine(" Method 1");
              count += 1;
          }
      });
      return count;
}

public static void Method2()
{
    for (int i = 0; i < 25; i++)
    {
        Console.WriteLine(" Method 2");
    }
}
public static void Method3(int count)
{
    Console.WriteLine("Total count is " + count);
}

在上面给出的代码中,Method 3需要一个参数,即Method 1的返回类型。在这里,await关键字对于等待Method 1任务的完成起着至关重要的作用。


四、asyncawait中常见问题总结

4.1 当方法用async标识时,编译器主要做了什么?

  • 告诉编译器这个方法里面可能会用到await关键字来标识该方法是异步的,如此之后,编译器将会在状态机中编译此方法。接着该方法执行到await关键字时会处于挂起的状态直到该异步动作完成后才恢复继续执行方法后面的动作。
  • 告诉编译器解析出方法的结果到返回类型中,比如说Task或者Task,也就是说将返回值存储到Task中,如果返回值为void那么此时应该会将可能出现的异常存储到上下文中。

4.2 当方法用async标识时,是不是所有调用者都将是异步?

当将方法用async标识时且返回值为void或者Task或者Task,此时该方法会在当前线程中一直同步执行。


用async标识方法并不会影响方法运行完成是否是同步或者异步,相反,它能够将方法划分成多块,有可能有些在异步中运行,以至于这些方法是异步完成的,而划分异步和同步方法的边界就是使用await关键字。也就是说如果在方法中未用到await关键字时则该方法就是一整块没有所谓的划分,会在同步中运行,在同步中完成。

4.3 当方法用async标识时,是否会引起方法的调用会被添加到线程池队列中或者是创建一个新的线程呢?

显然不是这样,当用async标识方法时只是显示告诉编译器在该方法中await关键字可能会被用到,当执行到await关键字开始处于挂起的状态知道异步动作执行完成才恢复(异步操作是在状态机中【有关状态机请看这里:Async和Await异步编程的原理】完成,完成后此时才会创建一个线程),这也就是为什么在方法中方法用async标识如果没有用到await关键字IDE会发出警告的原因。


到了这里我们可以得出结论:无论方法是同步还是异步都可以用async关键字来进行标识,因为用async标识只是显示表明在该方法内可能会用到await关键字使其变为异步方法,而且将该异步方法进行了明确的划分,只有用了await关键字时才是异步操作,其余一并为同步操作。

4.4 参数为什么不能使用ref和out关键字

我们知道用ref和out关键字不过是为了在方法里面改变其值,也就是是当同步完成时我们期望被ref或者out关键字修饰的值会被设置,但是它们可能在异步完成时或者之后才会被设置达不到我们预期,所以在异步方法中不能用ref和out关键字。

4.5 await关键字背后发生了什么

await关键字是这样用的

await Task.Run(() => "goyeer");

此时背后究竟发生了什么呢?我们上述也说过异步动作时在状态机中完成,当执行到这里时,编译器会自动生成代码来检测该动作是否已经完成,如果已经完成则继续同步执行await关键字后面的代码,通过判断其状态机状态若未完成则会挂起一个继续的委托为await关键字的对象直到完成为止,调用这个继续动作的委托重新进入未完成的这样一个方法。

五、总结

本节我们详细讲述了async和await关键字的使用和一些基本原理以及解释其原因,希望通过对本文的学习,对大家能够更好的去理解异步。

目录
相关文章
|
1月前
|
存储 开发框架 JSON
ASP.NET Core OData 9 正式发布
【10月更文挑战第8天】Microsoft 在 2024 年 8 月 30 日宣布推出 ASP.NET Core OData 9,此版本与 .NET 8 的 OData 库保持一致,改进了数据编码以符合 OData 规范,并放弃了对旧版 .NET Framework 的支持,仅支持 .NET 8 及更高版本。新版本引入了更快的 JSON 编写器 `System.Text.UTF8JsonWriter`,优化了内存使用和序列化速度。
|
3月前
|
数据库 开发者
.NET 异步编程之谜:async/await 模式究竟隐藏着怎样的神奇力量?
【8月更文挑战第28天】在当今注重效率和响应性的软件开发领域,.NET 的 async/await 模式如同得力助手,简化异步代码编写,使代码更易理解和维护。通过后台执行耗时操作,如网络请求和数据库查询,避免阻塞主线程,显著提升系统响应性。此模式不仅适用于网络请求,还广泛应用于数据库操作和文件读写。合理使用 async/await 可大幅优化性能,但需注意避免过度使用、正确处理调用链及异常,以确保系统稳定性和高效性。深入探索 async/await,助您构建更出色的应用程序。
52 0
|
1月前
|
存储 开发框架 .NET
浅析.NET6中的await原理
浅析.NET6中的await原理
43 1
|
2月前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
2月前
|
开发框架 .NET 中间件
ASP.NET Core Web 开发浅谈
本文介绍ASP.NET Core,一个轻量级、开源的跨平台框架,专为构建高性能Web应用设计。通过简单步骤,你将学会创建首个Web应用。文章还深入探讨了路由配置、依赖注入及安全性配置等常见问题,并提供了实用示例代码以助于理解与避免错误,帮助开发者更好地掌握ASP.NET Core的核心概念。
95 3
|
1月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架
|
2月前
|
开发框架 NoSQL .NET
利用分布式锁在ASP.NET Core中实现防抖
【9月更文挑战第5天】在 ASP.NET Core 中,可通过分布式锁实现防抖功能,仅处理连续相同请求中的首个请求,其余请求返回 204 No Content,直至锁释放。具体步骤包括:安装分布式锁库如 `StackExchange.Redis`;创建分布式锁服务接口及其实现;构建防抖中间件;并在 `Startup.cs` 中注册相关服务和中间件。这一机制有效避免了短时间内重复操作的问题。
|
3月前
|
开发框架 前端开发 中间件
聊聊 ASP.NET Core 中间件(二):中间件和筛选器的区别
聊聊 ASP.NET Core 中间件(二):中间件和筛选器的区别
121 1
|
3月前
|
开发框架 缓存 NoSQL
聊聊 ASP.NET Core 中间件(一):一个简单的中间件例子
聊聊 ASP.NET Core 中间件(一):一个简单的中间件例子
|
3月前
|
开发框架 .NET 数据库连接
闲话 Asp.Net Core 数据校验(三)EF Core 集成 FluentValidation 校验数据例子
闲话 Asp.Net Core 数据校验(三)EF Core 集成 FluentValidation 校验数据例子