.Net Core中无处不在的Async/Await是如何提升性能的?
一、简介
Async/Await在.Net Core中真的是无处不在,到处都是异步操作,那为什么要用?有什么作用?别人说能提升性能?网上一堆文章看的绕晕了也没说清楚,
所以这里从理论,实践,原理一个个解开这些疑问。
二、Async/Await有什么用?
1.Async/Await用法示例
用法很简单,这里就不详细说具体怎么用了,只提供一个示例,我们的目标是研究它的作用。
public class AsyncAwaitTest
{
public void Start()
{
Console.WriteLine($"aaa,线程Id:{Thread.CurrentThread.ManagedThreadId}");
AsyncMethod();
Console.WriteLine($"eee,线程Id:{Thread.CurrentThread.ManagedThreadId}");
Console.ReadLine();
}
public async Task<bool> AsyncMethod()
{
Console.WriteLine($"bbb,线程Id:{Thread.CurrentThread.ManagedThreadId}");
await Task.Run(() => { Thread.Sleep(500);
Console.WriteLine($"ccc,线程Id:{Thread.CurrentThread.ManagedThreadId}");
});
Console.WriteLine($"ddd,线程Id:{Thread.CurrentThread.ManagedThreadId}");
return true;
}
}
2.async/await的特点
1)不会阻塞线程
从示例的执行顺序,可以看出,当执行async/await方法时,主线程遇到await关键字,主线程就返回执行“eee”,然后释放,而不是等待,新开了一个子线程6执行另外的业务,await前面的方法还是主线程执行,await后面的方法,等线程6执行完了再继续执行。
2)同步的方式写异步
虽然是用了异步,但还是等待执行结果再往下执行,执行流程是同步的。
3.async/await能提升性能吗?
这个应该是大家最关心的问题了。
能提升单个请求的性能吗?
答案是不能的。很明显看的到,await等待了结果再执行后面的逻辑,还是串行的,执行完该多少秒还是多少秒, 中间还切换线程去处理了,相比同步来说还多了切换线程的损耗。
那async/await的意义何在?
在于多请求并发处理,且资源有限的时候,能增加吞吐量(单位时间处理的请求),增加cpu的利用率。
简单说就是有10个线程,每个线程的速度没有提升,然后居然QPS能提升?!
先来看一段微软官网的描述
此模型可很好地处理典型的服务器方案工作负荷。由于没有专用于阻止未完成任务的线程,因此服务器线程池可服务更多的Web请求。
考虑使用两个服务器:一个运行异步代码,一个不运行异步代码。对于本例,每个服务器只有5个线程可用于服务器请求。此字数太小,不切实际,仅供演示。
假设这两个服务器都接收6个并发请求。每个请求执行一个I/O操作。未运行异步代码的服务器必须对第6个请求排队,直到5个线程中的一个完成了I/O密集型工作
并编写了响应。此时收到了第20个请求,由于队列过长,服务器可能会开始变慢。
运行有异步代码的服务器也需要对第6个请求排队,但由于使用了async和await,I/O密集型工作开始时,每个线程都会得到释放,无需等到工作结束。
收到第20个请求时,传入请求队列将变得很小(如果其中还有请求的话),且服务器不会慢。
尽管这是一个人为想象的示例,但现实世界中其工作方式与此类似。事实上,相比服务器将线程专用于接收到的每个请求,使用async和await能够使
服务器处理一个数量级的请求。
注意上面官网描述的I/O密集型。什么样的是I/O密集型呢?,就是cpu性能必硬盘内存好太多,大部分时间都是cpu在等IO的读写操作。例如读文件,读文件的时候是不需要cpu参与的,只需要发一个命令给硬盘,硬盘读完文件会再通知cpu继续处理,这种叫DMA技术。
DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它是指一种高速的数据传输操作,允许在外部设备和存储器之间直接读写数据,既不通过cpu,也不需要cpu干预。
这个时候异步就显出它的优势来了,比如读文件需要1s,如果是同步操作,那个就有一个线程在等1s在往下执行。如果是异步的,读文件的时候,这个线程就释放了,等读完文件,硬盘通知cpu再
派一个线程接着处理,那中间的1秒,原来的线程就可以去处理其他请求了。
4.代码对照说明
public class HomeController : Controller
{
/// <summary>
/// 同步请求
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public string GetData()
{
var result = System.IO.File.ReadAllBytes(@"F:\package\package.rar");
return "ok";
} /// <summary>
/// 异步请求
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public async Task<string> GetDataAsync2()
{
var result = await System.IO.File.ReadAllBytesAsync(@"F:\package\package.rar");
return "ok";
}
}
同步请求的流程为
可以看出,硬盘在读取文件时,线程是在等待的,这时候线程1在这1s中是不工作的,空等状态。
异步请求的流程为
异步请求时,线程1遇到await关键字,发出命令就返回,然后释放掉了,硬盘读完数据会通知cpu,这时cpu派一个新的线程去接着处理,
因此,读文件的这1s,线程1可以去处理其它请求了,没有空等,这就是提高了cpu的利用率,单位时间内处理的请求数就变大了。
cpu密集型的异步是不能提高QPS的,下面代码就是cpu密集型的。
cpu密集型:计算密集型,硬盘、内存性能比cpu好很多,或不太需要访问I/O设备。
/// <summary>
/// 异步请求
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public async Task<string> GetDataAsync2()
{
await Task.Run(() => {
Thread.Sleep(100);//模拟业务处理耗时
});
return "ok";
}
这里前面主线程遇到await虽然释放了,但await里面又有一个线程接着工作,cpu(线程并没有空闲)
I/O密集型中IO的操作有哪些呢?
文件读写、http请求、数据库请求、redis请求。。。等等。
开发中哪些推荐用异步呢?
Web开发推荐、有Async的API的,Action、Filter、数据库访问、中间件等等。。。
.Net Core中无处不在的Async/Await是如何提升性能的?的更多相关文章
- 我也来说说C#中的异步:async/await
序 最近看了一些园友们写的有关于异步的文章,受益匪浅,写这篇文章的目的是想把自己之前看到的文章做一个总结,同时也希望通过更加通俗易懂的语言让大家了解"异步"编程. 1:什么是异步 ...
- ASP.NET Core Web 应用程序系列(四)- ASP.NET Core 异步编程之async await
PS:异步编程的本质就是新开任务线程来处理. 约定:异步的方法名均以Async结尾. 实际上呢,异步编程就是通过Task.Run()来实现的. 了解线程的人都知道,新开一个线程来处理事务这个很常见,但 ...
- C#异步中的Task,async,await
class Program { static void Main(string[] args) { Console.WriteLine("我是主线程,线程ID:{0}", Thre ...
- .Net Core中使用ref和Span<T>提高程序性能
一.前言 其实说到ref,很多同学对它已经有所了解,ref是C# 7.0的一个语言特性,它为开发人员提供了返回本地变量引用和值引用的机制. Span也是建立在ref语法基础上的一个复杂的数据类型,在文 ...
- 浅谈C#中的 async await 以及对线程相关知识的复习
C#5.0以后新增了一个语法糖,那就是异步方法async await,之前对线程,进程方面的知识有过较为深入的学习,大概知道这个概念,我的项目中实际用到C#异步编程的场景比较少,就算要用到一般也感觉T ...
- 【TypeScript】如何在TypeScript中使用async/await,让你的代码更像C#。
[TypeScript]如何在TypeScript中使用async/await,让你的代码更像C#. async/await 提到这个东西,大家应该都很熟悉.最出名的可能就是C#中的,但也有其它语言也 ...
- 你眼中的async/await是什么样的?
又到了周末的code review环节,这次code review发现了一个对async/await的理解问题.让我们直奔主题: var foodsSearch = new FoodSearchSer ...
- [原创.数据可视化系列之十二]使用 nodejs通过async await建立同步数据抓取
做数据分析和可视化工作,最重要的一点就是数据抓取工作,之前使用Java和python都做过简单的数据抓取,感觉用的很不顺手. 后来用nodejs发现非常不错,通过js就可以进行数据抓取工作,类似jqu ...
- Async/Await替代Promise的6个理由
译者按: Node.js的异步编程方式有效提高了应用性能:然而回调地狱却让人望而生畏,Promise让我们告别回调函数,写出更优雅的异步代码:在实践过程中,却发现Promise并不完美:技术进步是无止 ...
随机推荐
- K8s 资源配额管理对象 ResourcesQuota
Kubernetes 是一个多租户平台,更是一个镜像集群管理工具.一个 Kubernetes 集群中的资源一般是由多个团队共享的,这时候经常要考虑的是如何对这个整体资源进行分配.在 kubernete ...
- Python之基本数据类型与数据结构
一.基础数据类型 标准数据类型: ·不可变数据类型 Number(数字):int.float.bool.complex(复数) String(字符串) Tuple(元祖):不可变,无法通过下标来修改值 ...
- SpringBoot Log4j 安全漏洞分析及解决方案
一.序言 SpringBoot作为Java基础框架大行其道,前不久爆发出Log4j安全漏洞,大众更多关心Log4j的危害是多么严重,然而鲜有关心SpringBoot这一底层框架的安全性问题,换而言之, ...
- IIS部署.net core 的程序后,如何查看控制台的日志?
.net core 3.1 开发的web服务,本地开发的时候,双击运行 xxx.exe(.net core 3.1 发布后,文件夹里面有一个 .exe 文件,双击即可运行,会直接监听本地 xx端口测试 ...
- Java多线程基础-ThreadLocal
感谢原文作者:Yuicon 原文链接:https://segmentfault.com/a/1190000016705955 序 在多线程环境下,访问非线程安全的变量时必须进行线程同步,例如使用 sy ...
- 入门-k8s部署应用 (三)
Kubernetes 部署应用 在 k8s 上进行部署前,首先需要了解一个基本概念 Deployment Deployment 译名为 部署.在k8s中,通过发布 Deployment,可以创建应用程 ...
- 通过版本号来判断用户是否是第一次登陆----By张秀清
@interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)appl ...
- WebGPU 中的缓冲映射机制
1. 什么是缓冲映射 就不给定义了,直接简单的说,映射(Mapping)后的某块显存,就能被 CPU 访问. 三大图形 API(D3D12.Vulkan.Metal)的 Buffer(指显存)映射后, ...
- ROS::message_filters中的一个报错(mt::TimeStamp……)
『方便检索』 ros::Time msg_time = mt::TimeStamp<typename mpl::at_c<Messages, i>::type>::value( ...
- Docker 中的问题:”invalid reference format: repository name must be lowercase”
在导入镜像的时候出现问题:invalid reference format: repository name must be lowercase 问题解决:镜像命名不能出现大写字母,将大写改为小写即可 ...