飞道的博客

19:c# async await(by-朝夕)

350人阅读  评论(0)

前言

  1. C#5 (.NET4.5) 引入的语法糖
  2. C#7.1,Main入口也可以
  3. C#8.0,可以使用异步流await foreach和可释放对象 await using

番外-语法糖

  • 由编译器提供的便捷功能,就是语法糖
  • 也就是说IL是不变 没有升级的,但是在写代码时可以省略下,其中就靠编辑器干活儿
  • Lambda—匿名委托—new object{}匿名类—$”{}”
  • —自动属性get;set—var—using

await/async语法

  1. async 是用来修饰方法,如果单独出现,方法会警告,没有什么作用
  2. await在方法体内部,只能放在async修饰的方法内,必须放在task前面
  3. async/await方法里面如果没有返回值,默认返回一个Task,或者void(推荐用Task,而不是void,因为这样才能await/wait)
  4. 带async+await后,返回值要多一层Task<>

不带参数的异步方法

代码!

        private void asyncBtn_Click(object sender, EventArgs e)
        {
   
            DateTime beforeTime = System.DateTime.Now;
            asyncShow.Text += "执行《开始》\r\n";

            var ResultTask = AsyncMethod();

            DateTime afterTime = System.DateTime.Now;
            TimeSpan ts = afterTime.Subtract(beforeTime);
            asyncShow.Text += $"执行《结束》DateTime总共花费{ts.TotalMilliseconds}ms\r\n";
        }

        private async Task AsyncMethod()        //耗时的方法
        {
   
            await Task.Run(() =>
            {
   
                Thread.Sleep(3000);             //耗时操作
                this.Invoke(
                    new Action(() => asyncShow.Text += $"这是异步方法体内容\r\n")
                    );
            });
            asyncShow.Text += $"这是异步方法体内容后部分\r\n";
        }

执行效果

为什么是这样的效果呢?

  1. 首先按钮点击输出》》》执行《开始》
  2. 执行方法时遇到await就把await之前代码块内容执行。(并把后面程序块包成另一个方法进行执行)(子块)。此时程序块返回主方法,继续往下执行主方法!
  3. 主方法执行完成后,再返回(子块)进行执行后续代码。

带参数的异步方法

代码

        private async void asyncAddParam_Click(object sender, EventArgs e)
        {
   
            DateTime beforeTime = System.DateTime.Now;
            asyncAddParamTxt.Text += "执行《开始》\r\n";

            var ResultTask = AsyncMethodAddParam();
            //string result = ResultTask.Result;  //这里会产生死锁。程序卡死,因为在执行下边await的时候,会返回主程序,而主程序这会等ResultTask返回结果。陷入互相等待。

            //解决办法1----再开一个任务执行---包一层
            //Task.Run(() =>
            //{
   
            //    string result = ResultTask.Result; 

            //    this.Invoke(
            //        new Action(() => asyncAddParamTxt.Text += $"AsyncMethodAddParam:{result}\r\n")
            //    );
            //});
            //解决办法2---把本方法变为异步方法
            string result = await ResultTask;
            asyncAddParamTxt.Text += $"AsyncMethodAddParam:{result}\r\n";
            DateTime afterTime = System.DateTime.Now;
            TimeSpan ts = afterTime.Subtract(beforeTime);
            asyncAddParamTxt.Text += $"执行《结束》DateTime总共花费{ts.TotalMilliseconds}ms\r\n";
        }
        private async Task<string> AsyncMethodAddParam()
        {
   
            string result = await Task.Run(() =>
            {
   
                Thread.Sleep(3000);     //耗时操作
                this.Invoke(
                    new Action(() => asyncAddParamTxt.Text += $"这是带参数异步方法体内容\r\n")
                );
                return "带参数返回内容。";
            });
            return result;
        }

结果


这里的执行顺序有差别了!
因为在这里主方法也改为异步方法进行执行了。遇到await就返回。等后面执行完成后再返回进行输出。

等待结果

  1. t.Wait()
  2. Task.WaitAll()
  3. t.Result
  4. await t

老师写的方法

        private long GetCalculationAsync(long total)
        {
   
            var taskLong = Task.Run(() =>
             {
   
                 var task = this.CalculationAsync(total);
                 long lResult = task.Result;//子线程
                 return lResult;
             });
            return taskLong.Result;//主线程在等Result
        }

IL探究

Async+Task+await
主线程遇到await返回,把当下状态打包,交给线程池再次MoveNext


适合地方

不适合:Winform 调用await,被卡死。成功1失败2

适合:ASP.NET Core、Core WebApi、Console

提升性能?还是增加吞吐?

  1. 串行—没有并发—就不提升性能
  2. 性能:速度快慢—不能提升性能
  3. 吞吐:响应能力,1s能处理多少个请求—Web模式

还有线程协调的成本。。。更浪费?

ReadFile对比

  • Task:当然并发—10个线程
  • Async: 可以并发,但是并发不多—只有3个线程
  • Sync:同步,按顺序执行

这里的动作是读硬盘—都是读到当前程序里面,会很卡—不仅耗时而且卡

web

  • Task:耗时长一些,并发不够高------10个线程—铁打的10个线程
  • Async:并发高,速度快----少于10个线程,没有影响并发,能重用就是没事儿了,利用率高一些
  • Sync:串行的,耗时长

其实对电脑负荷比较小,

GetResponseAsync这里的线程呢? 对不起,这里没有!!!

DMA

硬件DMA技术, 带Async后缀的API
硬盘:接受命令—然后cpu忙自己的(线程)—写完/读完,会发中断信号,CPU再继续处理,这就基于DMA异步操作,就是可以节约CPU资源(线程)----
线程启动-等着-当然很浪费
用了异步就不用等

适合场景

跟第三方交互的(非托管资源,经常有async版本):
数据库openAsync-Redis
Web请求-Api
文件读取

Await为什么能提升吞吐—只负责发命令—然后就忙别的去了—不需要等待—事儿完成前就不浪费资源—完成后再来线程处理—这里还能复用
语法糖,同步方式写异步,增加系统吞吐量,一用到底,Web开发推荐

不适合场景

服务器本地计算(CPU密集型,托管资源):
大数据加减乘除,
数据处理

反而可能影响性能
但是用了没啥事儿


转载:https://blog.csdn.net/hello_mr_anan/article/details/116209010
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场