前言
- C#5 (.NET4.5) 引入的语法糖
- C#7.1,Main入口也可以
- C#8.0,可以使用异步流await foreach和可释放对象 await using
番外-语法糖
- 由编译器提供的便捷功能,就是语法糖
- 也就是说IL是不变 没有升级的,但是在写代码时可以省略下,其中就靠编辑器干活儿
- Lambda—匿名委托—new object{}匿名类—$”{}”
- —自动属性get;set—var—using
await/async语法
- async 是用来修饰方法,如果单独出现,方法会警告,没有什么作用
- await在方法体内部,只能放在async修饰的方法内,必须放在task前面
- async/await方法里面如果没有返回值,默认返回一个Task,或者void(推荐用Task,而不是void,因为这样才能await/wait)
- 带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";
}
执行效果
为什么是这样的效果呢?
- 首先按钮点击输出》》》执行《开始》
- 执行方法时遇到await就把await之前代码块内容执行。(并把后面程序块包成另一个方法进行执行)(子块)。此时程序块返回主方法,继续往下执行主方法!
- 主方法执行完成后,再返回(子块)进行执行后续代码。
带参数的异步方法
代码
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就返回。等后面执行完成后再返回进行输出。
等待结果
- t.Wait()
- Task.WaitAll()
- t.Result
- 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
提升性能?还是增加吞吐?
- 串行—没有并发—就不提升性能
- 性能:速度快慢—不能提升性能
- 吞吐:响应能力,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
查看评论