C# .net async await 学习
async/await简单介绍
在处理比较耗时的操作(如图片处理、数据压缩、http请求等)传统的异步方法是直接使用Thread或者Task进行操作,在复杂的应用编写中可能会出现回调的问题,因此C#目前主要推荐使用async/await来进行异步操作。也就是async/await主要用来异步回调问题, 而真正的异步操作还是用Task。
返回值
通常返回 Task 或 Task<TResult>。 在异步方法中,await 运算符应用于通过调用另一个异步方法返回的任务
如果方法包含指定 TResult 类型操作数的 return 语句,将 Task<TResult> 指定为返回类型,如果方法不含任何 return 语句或包含不返回操作数的 return 语句,将 Task 用作返回类型
异步方法也可以具有 void 返回类型。但是不推荐使用,因为无法等待具有 void 返回类型的异步方法,并且无效返回方法的调用方捕获不到异步方法引发的任何异常,而且也违背了我们使用他的初衷--解决异步回调问题
还需要注意:异步方法既不能声明任何 in、ref 或 out 参数,也不能具有引用返回值,但它可以调用具有此类参数的方法
实例
假如现在要做饭,需要做米饭2秒,做汤2秒;同步的方法就是先做米饭等待2秒,然后做汤等待2秒;异步的方法,米饭和汤同时做,一共花2秒
代码如下
class Program
{
private static Stopwatch stopwatch = new Stopwatch();
static void Main(string[] args)
{
stopwatch.Start();
DoCook();
Console.ReadLine();
}
/// <summary>
/// Cooking
/// </summary>
/// <returns></returns>
static async Task DoCook()
{
Console.WriteLine("Cook Start: " + stopwatch.ElapsedMilliseconds.ToString());
//case 1 异步Cooking
var rice = DoRice();
var soup = DoSoup();
await rice;
await soup;
Console.WriteLine($"Cook End: {stopwatch.ElapsedMilliseconds.ToString() } - {(rice.Result + soup.Result).ToString()}");
} /// <summary>
/// 做米饭,可以独立做
/// </summary>
/// <returns></returns>
static async Task<int> DoRice()
{
Console.WriteLine("DoRice Start: " + stopwatch.ElapsedMilliseconds.ToString());
var rice = ;
await Task.Run(() =>
{
Thread.Sleep();
rice = ;
});
Console.WriteLine("DoRice End: " + stopwatch.ElapsedMilliseconds.ToString());
return rice;
} /// <summary>
/// 做汤,可以独立做
/// </summary>
/// <returns></returns>
static async Task<int> DoSoup()
{
Console.WriteLine("DoSoup Start: " + stopwatch.ElapsedMilliseconds.ToString());
var soup = ;
await Task.Run(() =>
{
Thread.Sleep();
soup = ;
});
Console.WriteLine("DoSoup End: " + stopwatch.ElapsedMilliseconds.ToString());
return soup;
}
}
返回的结果
现在你女朋友很作,她非得吃蛋炒饭,蛋炒饭必须先做饭,假如做汤2秒,做蛋炒饭2秒钟,但是必须等米饭先做好
定义一个做蛋炒饭的方法
/// <summary>
/// 做蛋炒饭,需要先做米饭
/// </summary>
/// <returns></returns>
static async Task<int> DoEggRice()
{
Console.WriteLine("DoEggRice Start: " + stopwatch.ElapsedMilliseconds.ToString());
var rice = await DoRice();
var eggRice = ;
await Task.Run(() =>
{
Thread.Sleep();
eggRice = rice + ;
});
Console.WriteLine("DoEggRice End: " + stopwatch.ElapsedMilliseconds.ToString());
return eggRice;
}
然后开始
/// <summary>
/// Cooking
/// </summary>
/// <returns></returns>
static async Task DoCook()
{
Console.WriteLine("Cook Start: " + stopwatch.ElapsedMilliseconds.ToString());//case 3 异步EggCooking
var eggRice = DoEggRice();
var soup = DoSoup();
await eggRice;
await soup;
Console.WriteLine($"Cook End: {stopwatch.ElapsedMilliseconds.ToString() } - {(eggRice.Result + soup.Result).ToString()}");
}
结果如下
注意:
- 若某个函数F的函数体中需要使用await关键字的函数必须以async标记,进一步导致需要使用await调用F的那个函数也必须以async标记的情况
- await 表达式:用于异步方法内部,指出需要异步执行的任务。一个异步方法可以包含多个 await 表达式(不存在 await 表达式的话 IDE 会发出警告)
- var rice = DoRice(); rice.Result 属性为阻止属性。 如果你在其任务完成之前尝试访问它,当前处于活动状态的线程将被阻止,直到任务完成且值为可用。 在大多数情况下,应通过使用 await 访问此值,而不是直接访问属性
- 同步方法调用异步方法拿返回值会造成死锁.
引用问答
异步一定能提高效率吗?
不一定。异步本质上还是多线程,只是简化多线程的实现方式。至于使用多线程编程时能否提高程序执行效率,取决于 CPU 核心数,计算任务的复杂度以及该项任务本身是否适合被切分为并行计算模块。过于频繁地将不适合并行计算的任务拆分成异步编程中去,反而会导致密集计算性能的下降,因为此时线程池会疲于应对大量的线程调度操作。
有 async 一定要有 await 吗?不一定。在标记为 async 的方法中,不必须出现 await 关键字,只是若没有 await 关键字,这个方法不是真正意义上的异步方法,它会与普通方法一样是同步执行的。编译器不会报错,但会给出提示。
相反,若要使用 await 关键字,则必须在方法签名中包含 async 关键字。否则 await 将被当做标识符,而不能被当做一个关键字来处理。也就是说,当一个方法的签名中不包含 async 关键字时,你甚至可以在方法体中把 await 作为变量名。但这种操作是极其不推荐的,很容易造成误导。
异步方法的名称一定要以「Async」为结尾吗?
不一定。这只是习惯问题,就跟微软推荐所有的自定义特性后面都以「Attributes」为结尾一样,这不是必须的,只是如果大家都这样做了,理解起来更加方便一些。具体情况取决于不同场合下的规范要求。
使用 Task 并且 Run 了之后就实现异步了吗?
不是,这只是进行了一次多线程操作,后面的语句还是同步执行的。直到遇见 await 关键字,随着控制权的返回,才真正能实现异步。
异步是线程安全的吗?
理论上是的,这也是为什么异步编程模型能够极大地简化传统多线程操作所带来的各种问题的一大原因。尽管 await 所指的对象运行在其他线程上,但其后的语句还是会在原始线程上被执行。更深层次地说,后续的语句实际上是使用 Task 的 ContinueWith 方法来实现的。所以我们大可以放心的在异步方法中修改诸如 UI 元素等由主线程管理的资源。
但是,异步编程模型只是简化了这个过程,而不能替代我们解决具体的数据同步问题。如果在 await 之后有对其他共享资源的访问,而在 await 获取执行结果之前,这些资源已经被其他线程修改,那么 await 后续语句执行时所面对的数据内容将是不可预测的。
异步一定是返回控制权与等待结果同时进行的吗?
第一时间返回控制权是一定的,而等待与否要看任务执行的状态。当程序遇到 await 关键字时,如果 Task 所指代的对象以极快的速度完成,那么异步方法内部就会以同步执行的方式继续向后执行 await 语句后面的操作,不会产生等待。只有当 Task 没有执行完毕时,才会进行等待
参考文献
https://blog.csdn.net/qc530167365/article/details/83108848
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/
https://www.jianshu.com/p/1136e79d96e6
https://www.jianshu.com/p/8ea7ed4a2493
C# .net async await 学习的更多相关文章
- C# async await 学习笔记2
C# async await 学习笔记1(http://www.cnblogs.com/siso/p/3691059.html) 提到了ThreadId是一样的,突然想到在WinForm中,非UI线程 ...
- Async/Await 学习与示例
参考:Async/await学习 es 7 提供了对 promise 对象的更好的操作,省去了很多丧心病狂的链式异步请求,promise 是回调地狱的福音,而 Async/Await 则是 promi ...
- ES8之async/await学习随笔
详细学习参考文档: 阮一峰老师的博客,覆盖知识点ES6/7/8/9,本篇学习笔记对阮老师的关于async/await文档中的知识点进行分点总结 在ES8中加入async/await新特性后,很明显带来 ...
- async/await学习笔记
async/await 的目的是简化使用 promises 的写法. 让我们来看看下面的例子: // 一个标准的 JavaScript 函数 function getNumber1() { r ...
- C# async await 学习笔记1
由于我的开发工具为vs.net 2010(.net 4.0),需先做以下两步才能进行: 1.下载并安装Async CTP (http://www.microsoft.com/en-us/downloa ...
- C# async await 死锁问题总结
可能发生死锁的程序类型 1.WPF/WinForm程序 2.asp.net (不包括asp.net mvc)程序 死锁的产生原理 对异步方法返回的Task调用Wait()或访问Result属性时,可能 ...
- .NET异步操作学习之一:Async/Await中异常的处理
以前的异常处理,习惯了过程式的把出现的异常全部捕捉一遍,然后再进行处理.Async/Await关键字出来之后的确简化了异步编程,但也带来了一些问题.接下来自己将对这对关键字进行学习.然后把研究结果放在 ...
- JavaScript基础——深入学习async/await
本文由云+社区发表 本篇文章,小编将和大家一起学习异步编程的未来--async/await,它会打破你对上篇文章Promise的认知,竟然异步代码还能这么写! 但是别太得意,你需要深入理解Promis ...
- Koa2学习(二)async/await
Koa2学习(二)async/await koa2中用到了大量的async/await语法,要学习koa2框架,首先要好好理解async/await语法. async/await顾名思义是一个异步等待 ...
随机推荐
- 批量Ping执行Bash脚本
#!/bin/bash # Ping Batch Script # 连接超时时间 TMOUT= # 最大线程数 MAX_THREAD= # 保留内存大小 MIN_MEM= # 默认ip配置,可通过 - ...
- 笔记33 Spring MVC的高级技术——Spring MVC配置的替代方案
一.自定义DispatcherServlet配置 AbstractAnnotationConfigDispatcherServletInitializer所完成 的事情其实比看上去要多.在Spitt ...
- python_django_The requested URL /sunck/login/sunck/showmain/ was not found on this server.错误
在我url匹配过程中出现了这样一个错误: 网页显示: Not Found The requested URL /sunck/login/sunck/showmain/ was not found on ...
- 基于restframework进行token验证
一般情况下,进入到web网站主页都需要进行token或者其它验证,不能在没有登录的情况下可以查看主页的内容,在用户输入用户名密码后,进行校验成功,后台会返回一个token,用于用于下次访问主页或其它页 ...
- java动态代理--proxy&cglib
大纲 代理 proxy cglib 小结 一.代理 为什么要用代理?其实就是希望不修改对象的情况下,增强对象. 静态代理: 静态代理模式,需要代理类和目标类实现同一接口,代理类的方法调用目标类的方法, ...
- Servlet - request对象相关
request对象中封装了当前请求的所有请求信息, request对象由Tomcat服务器创建, 并作为实参传递给处理请求的Servlet的service()方法 1. 获取请求头数据 // 获取请求 ...
- CSS——浮动及应用&清除浮动
浮动(float) 1.普通流(normal flow) 这个单词很多人翻译为 文档流 , 字面翻译 普通流 或者标准流都可以. 前面我们说过,网页布局的核心,就是用CSS来摆放盒子位置.如何把盒子摆 ...
- JAVA单线程和多线程的实现方式
1.java单线程的实现 一个任务一个人独立完成 public class SingletonThread { @SuppressWarnings("static-acce ...
- NOI2019赛前两周被吊打记录
7.1 T1看了半天发现会个暴力FWT,然后突然返发现随便容斥一下就好了 T2猜了个只有13和23的,结果打个表发现伪了,然后标号不只一种连搜索都写错了,也没想过可以轮廓线dp,菜哭了o(╥﹏╥)o ...
- NX二次开发-UFUN获取圆柱的参数UF_MODL_ask_cylinder_parms
NX11+VS2013 #include <uf.h> #include <uf_modl.h> #include <uf_ui.h> UF_initialize( ...