首页 > 其他分享 >NetCore高级系列文章04---async、await原理揭秘

NetCore高级系列文章04---async、await原理揭秘

时间:2024-01-02 11:04:39浏览次数:25  
标签:__ 异步 04 NetCore await state num 线程 方法

一、async、await本质

直接说结论:它们是C#提供的语法糖,编译器编译后是状态机的调用。

先看如下的一段代码,要main方法中调用了三个await方法

NetCore高级系列文章04---async、await原理揭秘_异步方法

 将此dll进行反编译为4.0的代码如下:

NetCore高级系列文章04---async、await原理揭秘_异步方法_02

 可见到两个Main方法,也就是说我们在程序中Main方法上加了async关键词,编译器会编译成一个是异步的一个是非异步方法,程序还是将非异步的方法作为入口函数。进入函数

NetCore高级系列文章04---async、await原理揭秘_状态机_03

在该函数中调了异步的Main方法,再进入:

NetCore高级系列文章04---async、await原理揭秘_html_04

 在该函数中创建了一个状态机,将参数传给状态机,并调用期Start方法,可知异步方法实际上是状态机方法的调用

进入状态机类型<Main>d__0

private sealed class <Main>d__0 : IAsyncStateMachine
{
    public int <>1__state;

    public AsyncTaskMethodBuilder <>t__builder;

    public string[] args;

    private string <text>5__1;

    private HttpClient <httpClient>5__2;

    private string <html>5__3;

    private string <>s__4;

    private string <>s__5;

    private TaskAwaiter<string> <>u__1;

    private TaskAwaiter <>u__2;

    private void MoveNext()
    {
        int num = <>1__state;
        try
        {
            TaskAwaiter awaiter2;
            TaskAwaiter<string> awaiter;
            switch (num)
            {
            default:
                <httpClient>5__2 = new HttpClient();
                goto case 0;
            case 0:
                try
                {
                    TaskAwaiter<string> awaiter3;
                    if (num != 0)
                    {
                        awaiter3 = <httpClient>5__2.GetStringAsync("https://www.baidu.com").GetAwaiter();
                        if (!awaiter3.IsCompleted)
                        {
                            num = (<>1__state = 0);
                            <>u__1 = awaiter3;
                            <Main>d__0 stateMachine = this;
                            <>t__builder.AwaitUnsafeOnCompleted(ref awaiter3, ref stateMachine);
                            return;
                        }
                    }
                    else
                    {
                        awaiter3 = <>u__1;
                        <>u__1 = default(TaskAwaiter<string>);
                        num = (<>1__state = -1);
                    }
                    <>s__4 = awaiter3.GetResult();
                    <html>5__3 = <>s__4;
                    <>s__4 = null;
                    Console.WriteLine(<html>5__3);
                    <html>5__3 = null;
                }
                finally
                {
                    if (num < 0 && <httpClient>5__2 != null)
                    {
                        ((IDisposable)<httpClient>5__2).Dispose();
                    }
                }
                <httpClient>5__2 = null;
                awaiter2 = File.WriteAllTextAsync("E:\\test.txt", "zhengwei").GetAwaiter();
                if (!awaiter2.IsCompleted)
                {
                    num = (<>1__state = 1);
                    <>u__2 = awaiter2;
                    <Main>d__0 stateMachine = this;
                    <>t__builder.AwaitUnsafeOnCompleted(ref awaiter2, ref stateMachine);
                    return;
                }
                goto IL_015f;
            case 1:
                awaiter2 = <>u__2;
                <>u__2 = default(TaskAwaiter);
                num = (<>1__state = -1);
                goto IL_015f;
            case 2:
                {
                    awaiter = <>u__1;
                    <>u__1 = default(TaskAwaiter<string>);
                    num = (<>1__state = -1);
                    break;
                }
                IL_015f:
                awaiter2.GetResult();
                Console.WriteLine("写入成功");
                awaiter = File.ReadAllTextAsync("E:\\test.txt").GetAwaiter();
                if (!awaiter.IsCompleted)
                {
                    num = (<>1__state = 2);
                    <>u__1 = awaiter;
                    <Main>d__0 stateMachine = this;
                    <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
                    return;
                }
                break;
            }
            <>s__5 = awaiter.GetResult();
            <text>5__1 = <>s__5;
            <>s__5 = null;
            Console.WriteLine("文件内容" + <text>5__1);
        }
        catch (Exception exception)
        {
            <>1__state = -2;
            <text>5__1 = null;
            <>t__builder.SetException(exception);
            return;
        }
        <>1__state = -2;
        <text>5__1 = null;
        <>t__builder.SetResult();
    }

    void IAsyncStateMachine.MoveNext()
    {
        //ILSpy generated this explicit interface implementation from .override directive in MoveNext
        this.MoveNext();
    }

    [DebuggerHidden]
    private void SetStateMachine(IAsyncStateMachine stateMachine)
    {
    }

    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
    {
        //ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
        this.SetStateMachine(stateMachine);
    }
}

在此状态机类中可以看到我们自己写的Main方法中的主要代码已编译到了方法MoveNext()中,并将我们的局部变量编译成了成员变量

方法中有一个case,我们自己写的三个异步方法被编译后拆到了多个case中去了,MoveNext方法会根据不同的num被多次调用

编译的代码中可见到在每次调用异步方法时都会去判断是否完成

NetCore高级系列文章04---async、await原理揭秘_html_05

 

NetCore高级系列文章04---async、await原理揭秘_状态机_06

 

NetCore高级系列文章04---async、await原理揭秘_html_07

 

编译后的代码意思是当执行到string html = await httpClient.GetStringAsync("https://www.baidu.com");时,如果没有完成就直接返回了,并不会再往下执行

只有当此段代码执行完成后会继续往下执行,当执行到第二个异步方法await File.WriteAllTextAsync(@"E:\test.txt","zhengwei")时又会返回,等待执行完后再往下执行

同理,执行第三步异步方法var text = await File.ReadAllTextAsync(@"E:\test.txt");也是如此

所有异步方法都 执行完成后,会break;跳出状态机。

未完待续。。。

二、async背后的线程切换

await调用的等待期间,.net会把当前的线程返回线线程池,等异步方法调用执行完毕后,框架会从线程池再取出来一个线程执行后续的代码。

代码验证

NetCore高级系列文章04---async、await原理揭秘_状态机_08

 运行的结果可知在这个方法中使用的并不是同一个进程,一个是1,一个是9

当然,有时写入的内容少,也有可能方法开始和结束的线程id是一样的, 

三、异步方法与多线程的关系

异步方法的代码并不会自动在新的线程中执行,除非把代码放到新线程中执行。

在方法调用前和方法调用中用的是同一个线程,都是1,并没有开启一个新的线程

 

NetCore高级系列文章04---async、await原理揭秘_状态机_09

 

除非把这个异步方法放到一个新的线程中:可以看到方法调用中的线程为4,调用前的线程为1。

NetCore高级系列文章04---async、await原理揭秘_html_10

 

 

 

四、CancellationToken在异步方法中的使用

 



标签:__,异步,04,NetCore,await,state,num,线程,方法
From: https://blog.51cto.com/u_14316983/9064789

相关文章

  • 初中英语优秀范文100篇-044Can Money Buy Happiness?钱能买到幸福?
    PDF格式公众号回复关键字:SHCZFW044记忆树1Canmoneybuyhappiness?翻译钱能买到幸福吗简化记忆幸福句子结构主语:money(金钱)谓语:canbuy(能够购买)宾语:happiness(幸福)这是一个陈述句,谓语动词"canbuy"表达了金钱的购买能力。宾语"happiness"指的是幸福。整个句子在语......
  • 04.黑盒测试方法论 - 因果图
    因果图定义 因果图法是一种利用图解法分析输入的各种组合情况,从而设计测试用例的方法它适合于检查程序输入条件的各种组合情况“因”——输入条件“果”——输出结果因果图适用场景 描述多种条件的组合产生多个动作因果图中的基本符号 恒......
  • 2023-2024-1 20231304 《计算机基础与程序设计》第十四周学习总结
    2023-2024-120231304《计算机基础与程序设计》第十四周学习总结作业信息这个作业属于哪个课程2023-2024-1-计算机基础与程序设计这个作业要求在哪里2023-2024-1计算机基础与程序设计第十四周作业这个作业的目标自学教材《C语言程序设计》第13章并完成云班课测试......
  • 2023-2024 20231404高伟光《计算机基础与程序设计》第十四周学习总结
    作业信息作业内容我的班级我的班级作业要求第十四周要求作业目标学习c语言中文件操作作业正文此博客教材内容总结c语言程序设计第十三章讲了文件在c语言中的操作方法,包括了打开关闭,读出和写入,讲了文件操作的实际应用是指针的移动,所以又有了文件......
  • 初中英语优秀范文100篇-043Is Television Good or Bad?看电视是好是坏?
    PDF格式公众号回复关键字:SHCZFW043记忆树1Moreandmorepeoplelikewatchingtelevision.翻译越来越多的人喜欢看电视简化记忆电视句子结构1"Moreandmorepeople"是主语,表示越来越多的人。2"like"是谓语,表示喜欢或愿意。3"watchingtelevision"是宾语,表示......
  • 大数据分析与可视化 之 实验04 Pandas基础
    实验04Pandas基础实验学时:2学时实验类型:验证实验要求:必修一、实验目的1.掌握pandas系列、数据帧和面板的使用2.掌握pandas基本功能和操作二、实验要求Pandas程序的运行步骤。2.pandas的数据结构3.pandas系列、数据帧和面板pandas基本功能和操作三、实验内容任务1.......
  • Ftp基础(五):.NetCore中使用Ftp的建议(FluentFTP)
      上一篇说道C#使用FluentFTP来简单的连接使用Ftp,本篇是个人在.NetCore中使用Ftp的建议(可能有点啰嗦):  1、为Ftp的配置创建基类  在开发过程中,我们如果要使用Ftp,往往需要这几个信息:  Host:Ftp地址Port:端口号User:用户名Password:密码WorkingDirect......
  • 04VS+QT PCIE测速软件
    软件版本:vitis2021.1(vivado2021.1)操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!4.1概述经过前面章节的学习,如果读者应该已经掌握了PCIEXDMA方案的使用,那么我们知道QT可以设计出华丽的界面,那么本章......
  • 代码随想录day04 两两交换链表中的节点 删除链表的倒数第N个节点 链表相交 环形链表
    两两交换链表中的节点题目:这题画一下链表会比较清晰写写画画指针位置很快就可以写出来一开始以为一个tmp就够用了写着写着发现需要多一个代码:删除链表的倒数第N个节点:没什么思路只好先看看视频思路视频思路很简单也很清晰只需要两个指针一快一慢两指针的间......
  • [软件测试] 04 白盒 静态测试 习题
    提示:篇幅较长,可以使用Ctrl+F,在页面中快速查询关键词(或者你要找的题目)并跳转到指定的位置。关键词:白盒测试,静态测试判断题静态测试只能通过手工方式进行。答案:错误静态分析既可以发现程序中的语法错误,也可以检查和判定程序中的逻辑错误。答案:正确通过静态分析能够......