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()}");
}

结果如下

注意:

  1. 若某个函数F的函数体中需要使用await关键字的函数必须以async标记,进一步导致需要使用await调用F的那个函数也必须以async标记的情况
  2. await 表达式:用于异步方法内部,指出需要异步执行的任务。一个异步方法可以包含多个 await 表达式(不存在 await 表达式的话 IDE 会发出警告)
  3. var rice = DoRice();  rice.Result 属性为阻止属性。 如果你在其任务完成之前尝试访问它,当前处于活动状态的线程将被阻止,直到任务完成且值为可用。 在大多数情况下,应通过使用 await 访问此值,而不是直接访问属性
  4. 同步方法调用异步方法拿返回值会造成死锁.

引用问答

异步一定能提高效率吗?
不一定。异步本质上还是多线程,只是简化多线程的实现方式。至于使用多线程编程时能否提高程序执行效率,取决于 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 学习的更多相关文章

  1. C# async await 学习笔记2

    C# async await 学习笔记1(http://www.cnblogs.com/siso/p/3691059.html) 提到了ThreadId是一样的,突然想到在WinForm中,非UI线程 ...

  2. Async/Await 学习与示例

    参考:Async/await学习 es 7 提供了对 promise 对象的更好的操作,省去了很多丧心病狂的链式异步请求,promise 是回调地狱的福音,而 Async/Await 则是 promi ...

  3. ES8之async/await学习随笔

    详细学习参考文档: 阮一峰老师的博客,覆盖知识点ES6/7/8/9,本篇学习笔记对阮老师的关于async/await文档中的知识点进行分点总结 在ES8中加入async/await新特性后,很明显带来 ...

  4. async/await学习笔记

    async/await 的目的是简化使用 promises 的写法.     让我们来看看下面的例子: // 一个标准的 JavaScript 函数 function getNumber1() { r ...

  5. C# async await 学习笔记1

    由于我的开发工具为vs.net 2010(.net 4.0),需先做以下两步才能进行: 1.下载并安装Async CTP (http://www.microsoft.com/en-us/downloa ...

  6. C# async await 死锁问题总结

    可能发生死锁的程序类型 1.WPF/WinForm程序 2.asp.net (不包括asp.net mvc)程序 死锁的产生原理 对异步方法返回的Task调用Wait()或访问Result属性时,可能 ...

  7. .NET异步操作学习之一:Async/Await中异常的处理

    以前的异常处理,习惯了过程式的把出现的异常全部捕捉一遍,然后再进行处理.Async/Await关键字出来之后的确简化了异步编程,但也带来了一些问题.接下来自己将对这对关键字进行学习.然后把研究结果放在 ...

  8. JavaScript基础——深入学习async/await

    本文由云+社区发表 本篇文章,小编将和大家一起学习异步编程的未来--async/await,它会打破你对上篇文章Promise的认知,竟然异步代码还能这么写! 但是别太得意,你需要深入理解Promis ...

  9. Koa2学习(二)async/await

    Koa2学习(二)async/await koa2中用到了大量的async/await语法,要学习koa2框架,首先要好好理解async/await语法. async/await顾名思义是一个异步等待 ...

随机推荐

  1. vue实现京东动态楼层效果

    页面效果如下 <template> <div> <h1>首页</h1> <section class="floor-nav" ...

  2. 建站租用RAKsmart服务器的优势

    RAKsmart算是近年来受国内用户关注度颇高的美国服务器提供商.位于美国西海岸加州地区的RAKsmart机房,拥有超过十年的机房管理经验,提供了快速.稳定的服务器租用服务.那么RAKsmart服务器 ...

  3. pandas的read_csv踩到的坑

    read_csv要注意,如果没有设置index_col时,读出来的会在索引上方加上Unnamed:0.可以通过设置index_col来解决这个问题. import pandas as pd impor ...

  4. selenium提取不了标签文本

    1.举个例子:selenium使用driver.find_element_by_xpath().text 提取不到标签文本?? 如果我们提取的元素文本为空时,而不是我们想要的文本时,这时可能就是因为你 ...

  5. h5 input无法输入问题 屏蔽长按事件

    开发h5 app中突然发现在手机上长按文本会出现复制粘贴菜单,只要是文本长按都会出现这种情况确实有些不太符合交互,为此特意去翻了一下博客,得到了已下解决方案: 将所有元素的系统默认菜单禁用掉 *{ - ...

  6. jq-demo-阻止冒泡,阻止默认行为

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. 报错 DOMDocument not found

    php -m 查看有没有dom扩展 没有安装扩展 yum install php-dom php 常用扩展有 yum install php-solr php-opcache php-seasLog ...

  8. 引入CSS样式表(书写位置)

    CSS可以写到那个位置? 是不是一定写到html文件里面呢? 内部样式表 内嵌式是将CSS代码集中写在HTML文档的head头部标签中,并且用style标签定义,其基本语法格式如下: <head ...

  9. bzoj1034题解

    [解题思路] 广义田忌赛马的贪心模型.如果当前实力最差的马比对手实力最差的马强,则匹配:如果当前实力最强的马比对手实力最强的马强,亦匹配:若上述两点均不成立,拿己方最差的马去匹配对手最强的马.复杂度O ...

  10. bzoj1006题解

    [题意分析] 给你一张弦图,求图的最小染色数. [解题思路] 这篇讲稿已经讲得很详尽了.. 直接求完美消除序列,然后倒着染色即可.复杂度O(n2+nm). [参考程序] 求完美消除序列我是用的MCS( ...