async/Await使用和原理
await/async是.NetFramework4.5出现的,是语法糖,由编译器提供的功能!
await/async 是C#保留关键字,通常是成对出现,一般的建议是:要么不用,要么用到底
- async修饰方法,可以单独出现,但是没有任何意义,而且有警告
- await在方法体,只能出现在task/async方法前面,只有await会报错
下面来使用代码来剖析async和await的用法。
一:只有一个async没有await
/// <summary>
/// 只有async没有await,会有个warn
/// 跟普通方法没有区别
/// </summary>
private static async void NoReturnNoAwait()
{
//主线程执行
Console.WriteLine($"NoReturnNoAwait Sleep before Task,ThreadId={Thread.CurrentThread.ManagedThreadId}");
Task task = Task.Run(() =>//启动新线程完成任务
{
Console.WriteLine($"NoReturnNoAwait Sleep before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep();
Console.WriteLine($"NoReturnNoAwait Sleep after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}); //主线程执行
Console.WriteLine($"NoReturnNoAwait Sleep after Task,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
调用如下:
private async static Task Test()
{
Console.WriteLine($"start 当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("")}");
{
NoReturnNoAwait();
}
Console.WriteLine($"end Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Console.Read();
}
运行结果如下:
如果没有使用async,这就相当于一个普通的方法,另外注意的是方法的返回值使用Task接收,可以不用直接return
二:方法有async也有await
/// <summary>
/// async/await
/// 不能单独await
/// await 只能放在task前面
/// 不推荐void返回值,使用Task来代替
/// Task和Task<T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用。Async Void 不行
/// </summary>
private static async Task NoReturn()
{
//主线程执行
Console.WriteLine($"NoReturn Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
TaskFactory taskFactory = new TaskFactory();
Task task = taskFactory.StartNew(() =>
{
Console.WriteLine($"NoReturn Sleep before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep();
Console.WriteLine($"NoReturn Sleep after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}); await task;//主线程到这里就返回了,执行主线程任务
Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}"); //注意上面
// await task;
// Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
//等同于下面的代码
//task.ContinueWith(t =>
//{
// Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
//});
}
调用如下:
private async static Task Test()
{
Console.WriteLine($"start 当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("")}");
{
NoReturn();
for (int i = ; i < ; i++)
{
Thread.Sleep();
Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId.ToString("")} i={i}");
}
}
Console.WriteLine($"end Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Console.Read();
}
运行结果如下:
从上面结果可以看出:
1:主线程调用async/await方法,主线程遇到await返回执行后续动作,
2:await后面的代码会等着task任务的完成后再继续执行,其实就像把await后面的代码包装成一个continue的回调动作
3: 然后这个回调动作可能是Task线程,也可能是新的子线程,也可能是主线程
三:有返回值的task,如果要得到返回值,必须要t.Result
/// <summary>
/// 带返回值的Task
/// 要使用返回值就一定要等子线程计算完毕
/// </summary>
/// <returns>async 就只返回long</returns>
private static async Task<long> SumAsync()
{
Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
long result = ; await Task.Run(() =>
{
for (int k = ; k <; k++)
{
Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep();
}
for (long i = ; i < ; i++)
{
result += i;
}
}); Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
await Task.Run(() =>
{
for (int k = ; k <; k++)
{
Console.WriteLine($"SumAsync11111 {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep();
}
for (long i = ; i < ; i++)
{
result += i;
}
});
Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); return result;
}
调用如下:
private async static Task Test()
{
Console.WriteLine($"start 当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("")}");
{
Task<long> t = SumAsync();
Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
long result = t.Result;//访问result 主线程等待Task的完成 等价于t.Wait(); Console.WriteLine($"result=={result}");
}
Console.WriteLine($"end Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Console.Read();
}
得到的结果如下:
通过上面可以得到:如果使用t.Result 或者t.Wait()则相当于堵塞主线程,也就是等待子线程完成之后,主线程才能进行下面的操作,而await 则是不堵塞主线程
四:下面通过代码和反编译看一下async的底层是怎么实现的
public class AwaitAsyncILSpy
{
public static void Show()
{
Console.WriteLine($"start1 {Thread.CurrentThread.ManagedThreadId.ToString("")}");
Async();
Console.WriteLine($"aaa2 {Thread.CurrentThread.ManagedThreadId.ToString("")}");
}
private static async void Async()
{
Console.WriteLine($"ddd5 {Thread.CurrentThread.ManagedThreadId.ToString("")}");
await Task.Run(() =>
{
Thread.Sleep();
Console.WriteLine($"bbb3 {Thread.CurrentThread.ManagedThreadId.ToString("")}");
});
Console.WriteLine($"ccc4 {Thread.CurrentThread.ManagedThreadId.ToString("")}");
}
}
运行得到的结果根据上面的分析肯定是:15234
我们使用ILSPy来反编译dll,得到下图:
我们通过上图发现方法中加了async则会在反编译的时候增加的AsyncStateMachine状态(实现了IAsyncStateMachine接口),它实现的原理是:
初始化状态-1--执行就修改状态0--再执行就修改状态-1---执行就修改状态0---如果出现其他状态(-2)就结束了,就比如红绿灯一样,一样无限制的循环红灯-绿灯-红灯-绿灯
底层实现如下图:
async/Await使用和原理的更多相关文章
- C# Async/Await异步函数原理
原理 与同步函数相比,CLR在执行异步函数时有几个不同的特点: 1. 并非一次完成,而且分多次完成 2. 并非由同一个线程完成,而是线程池每次动态分配一个线程来处理: 结合 ...
- 关于异步执行(Async/await)的理解(转发)
原文地址: http://blog.jobbole.com/85787/ 同步编程与异步编程 通常情况下,我们写的C#代码就是同步的,运行在同一个线程中,从程序的第一行代码到最后一句代码顺序执行.而异 ...
- async/await 异步编程(转载)
转载地址:http://www.cnblogs.com/teroy/p/4015461.html 前言 最近在学习Web Api框架的时候接触到了async/await,这个特性是.NET 4.5引入 ...
- 进阶篇:以IL为剑,直指async/await
接上篇:30分钟?不需要,轻松读懂IL,这篇主要从IL入手来理解async/await的工作原理. 先简单介绍下async/await,这是.net 4.5引入的语法糖,配合Task使用可以非常优雅的 ...
- async/await 异步编程
前言 最近在学习Web Api框架的时候接触到了async/await,这个特性是.NET 4.5引入的,由于之前对于异步编程不是很了解,所以花费了一些时间学习一下相关的知识,并整理成这篇博客,如果在 ...
- .NET 中的 async/await 异步编程
原文出处: Teroy 的博客 前言 最近在学习Web Api框架的时候接触到了async/await,这个特性是.NET 4.5引入的,由于之前对于异步编程不是很了解,所以花费了一些时间学习一下相关 ...
- C#异步编程由浅入深(二)Async/Await的作用.
考虑到直接讲实现一个类Task库思维有点跳跃,所以本节主要讲解Async/Await的本质作用(解决了什么问题),以及Async/Await的工作原理.实现一个类Task的库则放在后面讲.首先回顾 ...
- 温故知新,CSharp遇见异步编程(Async/Await),聊聊异步编程最佳做法
什么是异步编程(Async/Await) Async/Await本质上是通过编译器实现的语法糖,它让我们能够轻松的写出简洁.易懂.易维护的异步代码. Async/Await是C# 5引入的关键字,用以 ...
- Atitit. Async await 优缺点 异步编程的原理and实现 java c# php
Atitit. Async await 优缺点 异步编程的原理and实现 java c# php 1. async & await的来源1 2. 异步编程history1 2.1. 线程池 2 ...
随机推荐
- Linux 下配置Nginx,MySql,php-fpm开机启动
一. Nginx 开机启动 1.在/etc/init.d/目录下创建脚本 vim /etc/init.d/nginx 2.编写脚本内容 (将以下复制进去相应改动安装路径) #!/bin/bash # ...
- Guess 任意猜
age_of_oldboy = 56 count = 0 while count <3: guess_age = int(input("guess age:")) if gu ...
- XSS攻击(出现的原因、预防措施......)
验证XSS攻击重点不是去查找可输入哪些内容会出现什么样的bug就是测试XSS攻击,重点是了解它出现的原理,为什么会出现XSS攻击,导致一些问题出现?如何防御与解决XSS攻击?以下我将简单介绍以上提出的 ...
- eclipse使用Git基本流程
1.安装GIT 2.Git的使用 ①下载代码到eclipse(右键导入工程) ②提交代码到本地(commit) ③更新代码到本地(pull) ④当本地出现冲突时,解决冲突,没有冲突当然就最好啦 ⑤提交 ...
- python --- 快速排序算法
在快速排序中引入递归和分治的概念(关于递归和分治的概念会单独写一篇来进行介绍) 问的解决思路: 快速排序的基本思想本身就是分治法,通过分割,将无序序列分成两部分,其中前一部分的元素值都要小于后一部分的 ...
- Visio打开或取消箭头的自动吸附和自动连接
在用Visio画图时Visio的自动对齐.自动连接.自动吸附功能确实能带了很多便利.但在画连接线时,Visio总是自动连接箭头与图形的固定节点,想要微调一下连接位置,就显得很不方便,需要关闭自动连接功 ...
- RabbitMq在CentOs7下的完整安装步骤,带你踩坑
1.前言 因为公司项目中用的RabbitMq来做消息处理,自己以前没有接触过,所以想自学一下.然额,光安装就花了6.7个小时才搞定,中间还换过一个版本,综合国内外博客才最终将所有安装中遇到的问题解决掉 ...
- .NET Core之微信支付之公众号、H5支付篇
前言 本篇主要记录微信支付中公众号及H5支付全过程. 准备篇 公众号或者服务号(并开通微信支付功能).商户平台中开通JSAPI支付.H5支付. 配置篇 公众号或者服务号中 -------开发----- ...
- 卷积神经网络之AlexNet
由于受到计算机性能的影响,虽然LeNet在图像分类中取得了较好的成绩,但是并没有引起很多的关注. 知道2012年,Alex等人提出的AlexNet网络在ImageNet大赛上以远超第二名的成绩夺冠,卷 ...
- MySQL5.7下面,误操作导致的drop table db1.tb1; 的恢复方法:
MySQL5.7下面,误操作导致的drop table db1.tb1; 的恢复方法: 0.停业务数据写入.[iptables封禁] 1.从备份服务器上拉取最新的一个全备文件,恢复到一个临时的服务器上 ...