广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#异步编程async/await用法详解
  • 279
分享到

C#异步编程async/await用法详解

2024-04-02 19:04:59 279人浏览 八月长安
摘要

异步函数简介 一般指 async 修饰符声明得、可包含await表达式得方法或匿名函数。 声明方式 异步方法的声明语法与其他方法完全一样, 只是需要包含 async 关键字。asyn

异步函数简介

一般指 async 修饰符声明得、可包含await表达式得方法或匿名函数。

声明方式

异步方法的声明语法与其他方法完全一样, 只是需要包含 async 关键字。async可以出现在返回值之前的任何位置, 如下示例:

        async public static void GetInfoAsync()
        {
           //...
        }

        public async static void GetInfoAsync()
        {
           //...
        }

        public static async void GetInfoAsync()
        {
            //...
        }

异步方法的返回类型

异步函数的返回类型只能为: void、Task、Task<TResult>。

Task<TResult>: 代表一个返回值T类型的操作。

Task: 代表一个无返回值的操作。

void: 为了和传统的事件处理程序兼容而设计。

await(等待)

await等待的是什么? 可以是一个异步操作(Task)、亦或者是具备返回值的异步操作(Task<TResult>)的值, 如下:

        public async static void GetInfoAsync()
        {
            await GetData(); // 等待异步操作, 无返回值
            await GetData<int>(1); //等待异步操作, 返回值 int
        }

        static Task GetData()
        {
            //...
            return null;
        }

        static Task<T> GetData<T>(int a)
        {
            //...
            return null;
        }

注: await 最终操作的是一个值, 当然, 也可以是无值, 如上GetData() , 否则就是一个 Task<T> 如上: GetData<T>()

await执行过程

TaskAwaiter 获取执行结果

一般而言, await等待的一个异步操作, 无论是具备返回值还是否, 那么最终都会获得该操作是否已完成、具备返回值得异步操作可以获取他得返回结果。

所以这个时候,TaskAwaiter出现了, 无论是Task、还是Task<TResult>操作, 都具备GetAwaiter() 方法。

用于获取改操作得状态、返回结果, 及部分操作, 如下TaskAwaiter结构:

    //
    // 摘要:
    //     提供等待异步任务完成的对象。
    public struct TaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion
    {
        //
        // 摘要:
        //     获取一个值,该值指示是否已完成的异步任务。
        //
        // 返回结果:
        //     true 如果任务已完成;否则为 false。
        //
        // 异常:
        //   T:System.NullReferenceException:
        //     System.Runtime.CompilerServices.TaskAwaiter 对象未正确初始化。
        public bool IsCompleted { get; }

        //
        // 摘要:
        //     结束异步任务完成之前的等待。
        //
        // 异常:
        //   T:System.NullReferenceException:
        //     System.Runtime.CompilerServices.TaskAwaiter 对象未正确初始化。
        //
        //   T:System.Threading.Tasks.TaskCanceledException:
        //     任务已取消。
        //
        //   T:System.Exception:
        //     在完成的任务 System.Threading.Tasks.TaskStatus.Faulted 状态。
        [TargetedPatchinGoptOut("PerfORMance critical to inline across NGen image boundaries")]
        public void GetResult();
        //
        // 摘要:
        //     设置时应执行的操作 System.Runtime.CompilerServices.TaskAwaiter 对象停止等待异步任务完成。
        //
        // 参数:
        //   continuation:
        //     要在等待操作完成时执行的操作。
        //
        // 异常:
        //   T:System.ArgumentNullException:
        //     continuation 为 null。
        //
        //   T:System.NullReferenceException:
        //     System.Runtime.CompilerServices.TaskAwaiter 对象未正确初始化。
        [SecuritySafeCritical]
        public void OnCompleted(Action continuation);
        //
        // 摘要:
        //     计划程序与此等待异步任务的延续任务操作。
        //
        // 参数:
        //   continuation:
        //     要等待操作完成时调用的操作。
        //
        // 异常:
        //   T:System.ArgumentNullException:
        //     continuation 为 null。
        //
        //   T:System.InvalidOperationException:
        //     该等待程序未正确初始化。
        [SecurityCritical]
        public void UnsafeOnCompleted(Action continuation);
    }

接下来, 演示如何通过等待去获取异步操作的返回结果, 如下代码所示:

        public async static void GetInfoAsync()
        {
            Task<bool> task = Task.Run<bool>(() =>
            {
                Thread.Sleep(10000); //模拟耗时
                return true;
            });
            
            //以下两种方式
            bool taskResult1 = await task;  //内部自己执行了GetAwaiter() 
            bool taskResult = task.GetAwaiter().GetResult();  //自己手动执行Awaiter(), 但是阻塞UI
       Console.WriteLine(taskResult);
        }

注: 对于一个await表达式, 编译器生成的代码会先调用GetAwaiter(), 然后通过awaiter得成员来等待结果, 所以以上两种方式等效( 不考虑阻塞的情况下)

为了验证以上猜测, 通过反编译工具查看得到如下代码:

编译器最终生成两个密封类, 一个类( <>c )我们展开分析:

<GetInfoAsync>b__1_0() 正是模拟耗时的一个操作委托生成的方法。

        [CompilerGenerated]
        [Serializable]
        private sealed class <>c
        {
            public static readonly Program.<>c <>9 = new Program.<>c();
            public static Func<bool> <>9__1_0;
            internal bool <GetInfoAsync>b__1_0()
            {
                Thread.Sleep(10000);
                return true;
            }
        }

第二个类<GetInfoAsync>d__1 分析:

该类分别实现了接口 IAsyncStateMachine 的MoveNext() 与 SetStateMachine() ,另外 注意,

还特别定义了一个 <>t__builder, 先记住他, 下面讲会对他讲到, 为什么编译器生成的代码会默认先调用GetAwaiter()

 [CompilerGenerated]
         private sealed class <GetInfoAsync>d__1 : IAsyncStateMachine
         {
             public int <>1__state;
             public AsyncVoidMethodBuilder <>t__builder;
             private Task<bool> <task>5__1;
             private bool <result>5__2;
             private bool <>s__3;
             private TaskAwaiter<bool> <>u__1;
             void IAsyncStateMachine.MoveNext()
             {
                 int num = this.<>1__state;
                 try
                 {
                     TaskAwaiter<bool> awaiter;
                     if (num != 0)
                     {
                         Func<bool> arg_2F_0;
                         if ((arg_2F_0 = Program.<>c.<>9__1_0) == null)
                         {
                             arg_2F_0 = (Program.<>c.<>9__1_0 = new Func<bool>(Program.<>c.<>9.<GetInfoAsync>b__1_0));
                         }
                         this.<task>5__1 = Task.Run<bool>(arg_2F_0);
                         awaiter = this.<task>5__1.GetAwaiter();
                         if (!awaiter.IsCompleted)
                         {
                             this.<>1__state = 0;
                             this.<>u__1 = awaiter;
                             Program.<GetInfoAsync>d__1 <GetInfoAsync>d__ = this;
                             this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<bool>, Program.<GetInfoAsync>d__1>(ref awaiter, ref <GetInfoAsync>d__);
                             return;
                         }
                     }
                     else
                     {
                         awaiter = this.<>u__1;
                         this.<>u__1 = default(TaskAwaiter<bool>);
                         this.<>1__state = -1;
                     }
                     this.<>s__3 = awaiter.GetResult();
                     this.<result>5__2 = this.<>s__3;
                     Console.WriteLine(this.<result>5__2);
                 }
                 catch (Exception exception)
                 {
                     this.<>1__state = -2;
                     this.<>t__builder.SetException(exception);
                     return;
                 }
                 this.<>1__state = -2;
                 this.<>t__builder.SetResult();
             }
             [DebuggerHidden]
             void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
             {
             }
         }

接下来, 看GetInfoAsync()方法, 这个是自己编写的, 但是实现的细节,最终转换成了编译器执行代码:

        [AsyncStateMachine(typeof(Program.<GetInfoAsync>d__1)), DebuggerStepThrough]
        public static void GetInfoAsync()
        {
            Program.<GetInfoAsync>d__1 <GetInfoAsync>d__ = new Program.<GetInfoAsync>d__1();
            <GetInfoAsync>d__.<>t__builder = AsyncVoidMethodBuilder.Create();
            <GetInfoAsync>d__.<>1__state = -1;
            AsyncVoidMethodBuilder <>t__builder = <GetInfoAsync>d__.<>t__builder;
            <>t__builder.Start<Program.<GetInfoAsync>d__1>(ref <GetInfoAsync>d__); //注意到该代码, 调用了Start(),也许这就是默认实现的地方
        }

通过查看Start泛型方法的实现, 最终找到了, 该泛型的条件限制于必须实现与IAsyncStateMachine 接口, 所以通过查看, 该类最终调用了 MoveNext(), 而MoveNext中正

调用了GetAwaiter()。关于Start的实现如下所示:

[SecuritySafeCritical, DebuggerStepThrough, __DynamicallyInvokable]
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
    if (stateMachine == null)
    {
        throw new ArgumentNullException("stateMachine");
    }
    ExecutionContextSwitcher executionContextSwitcher = default(ExecutionContextSwitcher);
    RuntimeHelpers.PrepareConstrainedRegions();
    try
    {
        ExecutionContext.EstablishCopyOnWriteScope(ref executionContextSwitcher);
        stateMachine.MoveNext();
    }
    finally
    {
        executionContextSwitcher.Undo();
    }
}

剖析MoveNext

对比IDE中的代码, 如下所示:

总结

await等待的是任务的操作值, 最终返回是异步操作的返回结果。而这一切都是因为编译器创建了一系列复杂的状态机制, 以达到其实现。

到此这篇关于C#异步编程async/await用法详解的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: C#异步编程async/await用法详解

本文链接: https://www.lsjlt.com/news/163843.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C#异步编程async/await用法详解
    异步函数简介 一般指 async 修饰符声明得、可包含await表达式得方法或匿名函数。 声明方式 异步方法的声明语法与其他方法完全一样, 只是需要包含 async 关键字。asyn...
    99+
    2022-11-13
  • C#异步编程之async/await详解
    目录概述C#异步编程用法async/await和Task简介asyncawaitTask其他实现原理剖析实现原理示例概述 异步这个概念在不同语境下有不同的解释,比如在一个单核CPU里...
    99+
    2023-03-11
    C#异步编程async await C#异步编程 C# async await
  • JS异步编程之generator与async/await语法糖详解
    目录Generator 异步方案async/awaitGenerator 异步方案 相比于传统回调函数的方式处理异步调用,Promise最大的优势就是可以链式调用解决回调嵌套的问题。...
    99+
    2022-11-13
    JS generator async/await语法糖 JS generator JS async await
  • C#异步编程之async/await怎么使用
    今天小编给大家分享一下C#异步编程之async/await怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。概述异步这个...
    99+
    2023-07-05
  • C#使用async和await实现异步编程
    最近在写程序的时候,经常遇到大量需要异步访问的情况,但是对于async和await到底怎么写,还不是非常明确。 1.普通的程序怎么写? class Program { sta...
    99+
    2022-11-13
  • C#怎么使用async和await实现异步编程
    这篇文章主要介绍“C#怎么使用async和await实现异步编程”,在日常操作中,相信很多人在C#怎么使用async和await实现异步编程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#怎么使用async...
    99+
    2023-07-02
  • C#5.0中的异步编程关键字async和await
    一、Asynchronous methods 异步方法 .NET 4.5 的推出,对于C#又有了新特性的增加——就是C#5.0中async和await两个关键...
    99+
    2022-11-13
  • .NET实现异步编程async和await
    await和async是.NET Framework4.5框架、C#5.0语法里面出现的,await和async是语法糖。 注意: 1、async出现在方法的声明里面,任何一个方法都...
    99+
    2022-11-13
  • C#异步编程由浅入深(二)之Async/Await的使用
      考虑到直接讲实现一个类Task库思维有点跳跃,所以本节主要讲解Async/Await的本质作用(解决了什么问题),以及Async/Await的工作原理。实现一...
    99+
    2022-11-13
  • JS中的async与await异步编程及await使用陷阱
    ECMA2017中新加入了两个关键字async与await 简单来说它们是基于promise之上的的语法糖,可以让异步操作更加地简单明了 首先我们需要用async关键字,将函数标记为...
    99+
    2023-03-24
    async与await异步编程 async与await
  • C#多线程系列之async和await用法详解
    目录async和awaitasyncawait从以往知识推导创建异步任务创建异步任务并返回Task异步改同步说说 await Task说说 async Task<TR...
    99+
    2022-11-13
  • async-await消灭异步回调实例详解
    目录引言一、走进Async-await原理1、原理12、原理23、原理34、原理4二、深入Async-await规则1、async封装Promise2、await相当于then3、多...
    99+
    2022-11-13
  • 使用Node.js的async和await进行异步编程
    Node.JS官方文档:https://nodejs.dev/en/ 创建异步函数,并返回相关数值: 一般方式创建 function fn(){ return Promi...
    99+
    2023-05-18
    Node.js async和await Node.js 异步编程
  • .NET怎么实现异步编程async和await
    本篇内容介绍了“.NET怎么实现异步编程async和await”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!await和async是.NET...
    99+
    2023-06-29
  • 如何解析异步编程In .NET APM/EAP和async/await
    如何解析异步编程In .NET APM/EAP和async/await,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。概述在之前写的一篇关于async和await的前世今生的文章...
    99+
    2023-06-17
  • 关于C#中async/await的用法实例详解
    一直对c#中async/await的用法模模糊糊,不太清晰,今天写了一下Demo彻底明确一下async/await的用法,以免因为对其不了解而对后期的业务产生影响(比如事务导致的锁表...
    99+
    2023-02-08
    C#中async/await的用法 C#中async/await
  • JavaScript异步编程中async函数详解
    目录async函数await 表达式async使用形式async读取文件async发送AJAX请求与生成器(Generator)相比async函数 async函数的返回值为 prom...
    99+
    2022-11-13
    JavaScript async JavaScript异步编程 JS async
  • 如何用ES7中的Async和Await进行异步编程
    这篇文章给大家介绍如何用ES7中的Async和Await进行异步编程,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Async/Await基本规则async 表示这是一个async函数,...
    99+
    2022-10-19
  • 怎么使用c#异步操作async await状态机
    本篇内容介绍了“怎么使用c#异步操作async await状态机”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!async awai...
    99+
    2023-07-05
  • JS中的async与await异步编程及await使用陷阱源码分析
    这篇“JS中的async与await异步编程及await使用陷阱源码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JS中...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作