首页 新闻 会员 周边

感觉async await 异步编程 并不能提升性能啊?

0
悬赏园豆:30 [已解决问题] 解决于 2019-12-06 09:55

我有2个方法 代码相同
都是执行写入文件IO操作 一个同步 一个异步

然后我用POSTMAN 分别用200个线程 去同时测试2个接口

结果很意外 2个接口 同时执行完成的速度 异步更慢

之前经常看别人博主说 尽量用异步来优化自己的代码

但是经过自己测试后 发现使用异步的效率结果更差,后面仔细想了下 好像确实是这么回事

所谓的异步操作就是一个A线程在执行任务的时候,执行到一半 再把任务交给B另一个线程,

然后A线程就开始等待B的执行完成了,那这不还是同步的吗? 还是我理解的有问题呢?

阿爆g的主页 阿爆g | 初学一级 | 园豆:20
提问于:2019-12-05 10:39
< >
分享
最佳答案
0

你的感觉没有错,异步编程不能提高性能。异步编程只是提供一种简单的编程模型来提高系统的响应能力,比如,如果在UI线程上执行长时间IO操作,在操作完成之前界面就处在无法操作的状态。
可以提高性能的是并行技术,比如任务并行库(TPL,Task Parallel Library)、并行LINQ(PLINQ)等,这些技术可以充分利用CPU来提高计算性能。
一般来说,耗时的IO操作使用异步简化代码,耗时的计算操作使用并行来提高性能

收获园豆:30
拓拓 | 小虾三级 |园豆:1050 | 2019-12-05 13:48
其他回答(7)
0

只是提高了线程的利用率,比如本来50个线程只能处理1000个并发,使用 async/await 后50个线程可以处理5000个并发

dudu | 园豆:31003 (高人七级) | 2019-12-05 10:42

从单纯的性能角度看, async/await 反而增加了线程切换的开销

支持(1) 反对(1) dudu | 园豆:31003 (高人七级) | 2019-12-05 10:43

但是感觉说不通啊
比如我用POSTMAN 请求50次
同步的话 就是50个线程在执行50个请求
异步的话 就是100个线程执行50个请求 50个等待完成 50个执行上传
这不是增加了线程的开销吗?

支持(0) 反对(0) 阿爆g | 园豆:20 (初学一级) | 2019-12-05 10:50
0

和你有过同样的疑惑。
目前自己的理解是,比如服务端最大处理请求是100个线程,那么同步模式下,150个请求过来,就有50个请求需要等待执行。async await 模式下,正在执行的100个线程 可以空闲出来 处理后来的50个请求,前面100个请求异步完成后,再通过上下文切换到当前的100个线程,处理完后续的流程。工作线程是在不停的切换过程中提升了 并发效率。
而在单个请求中,async await是有线程上下文切换的性能损耗,所以在处理一个本来就很【快速】的逻辑例如读一个Redis缓存,那么性能会有比较显著的下降。

gt1987 | 园豆:1150 (小虾三级) | 2019-12-05 13:48

但是感觉说不通啊
比如我用POSTMAN 请求50次
同步的话 就是50个线程在执行50个请求
异步的话 就是100个线程执行50个请求 50个等待完成 50个执行上传
这不是增加了线程的开销吗?

支持(0) 反对(0) 阿爆g | 园豆:20 (初学一级) | 2019-12-05 15:54

@阿爆g: 提高了服务端的并发能力

支持(0) 反对(0) gt1987 | 园豆:1150 (小虾三级) | 2019-12-05 16:13

@xiaogui340: 可是 明明只需要50个线程 但是用到了100个线程啊
还有50个也没事情干啊 在等待啊

就相当于 明明50个人能搞定 非要让100个人弄 还有50个闲着

支持(0) 反对(0) 阿爆g | 园豆:20 (初学一级) | 2019-12-05 17:51

@阿爆g:

最后一句理解有误,50个并没有闲着,而是去处理更多的请求去了;

真实情况,不是只有50个请求进来就完事了,而是持续的每秒都有50个请求进来。

支持(0) 反对(0) 码农搞事情 | 园豆:20 (初学一级) | 2019-12-05 18:12
0

这里 举一个这样的例子吧
去快餐店的时候,在你点完菜之后,其他人不会点任何东西,直到你吃完为止。使用async/ await,其他人可以在你点完菜之后下他们的订单,并且可以同时处理多个订单。

初夏的阳光丶 | 园豆:641 (小虾三级) | 2019-12-05 13:48

但是感觉说不通啊
比如我用POSTMAN 请求50次
同步的话 就是50个线程在执行50个请求
异步的话 就是100个线程执行50个请求 50个等待完成 50个执行上传
这不是增加了线程的开销吗?

支持(0) 反对(0) 阿爆g | 园豆:20 (初学一级) | 2019-12-05 15:54

@阿爆g: 这么说吧,你去购物的时候,原本收银台只有一个,你需要等待前面的人结算完成之后才能轮到你去买单,但是现在突然增加了几个收银台,你就可以去换一个收银台结算。而你说的增加的线程的开销 就好比我多开几个收银台,需要聘请更多的人。需要支付更多的工资,但是你结算的速度快了。你的营业额也就多了起来。

支持(0) 反对(0) 初夏的阳光丶 | 园豆:641 (小虾三级) | 2019-12-05 15:58

@初夏的阳光丶: 感觉并不是这样理解的
等待的线程还是在等待闲着啊 并没有处理其它任务

明明只需要50个线程 但是现在用到了100个线程 还有50个也没事情干啊 在等待啊
就相当于 明明50个人能搞定 非要让100个人弄 还有50个闲着

支持(0) 反对(0) 阿爆g | 园豆:20 (初学一级) | 2019-12-05 17:52
0

如果你参与过高并发的项目,就会切身体会到异步的效果;

对于低并发的项目,绝大部分情况没有必要使用异步编程(除非要并行的执行多个耗时并且不需要返回结果的任务)

码农搞事情 | 园豆:20 (初学一级) | 2019-12-05 17:44

我知道 多线程的好处 我这里只是想了解下
每个地方都用异步是否合理 因为看了些博主说 尽量用异步优化所有代码
不需要等待结果的任务 毕竟很少

支持(0) 反对(0) 阿爆g | 园豆:20 (初学一级) | 2019-12-05 17:49

用你举的例子;

比如我用POSTMAN 请求50次
同步的话 就是50个线程在执行50个请求
异步的话 就是100个线程执行50个请求 50个等待完成 50个执行上传
------------------------------------------------
假如你的IIS主线程,最高只能接受25个并发;
同步的话会有25个请求会返回失败;
而异步的话会开子线程来处理上传任务,主线程就可以去处理更多的请求;
------------------------------------------------
那么就结果就是50个并发请求进来,同步只能处理25个,而异步可以处理三四十个甚至更多;

支持(0) 反对(0) 码农搞事情 | 园豆:20 (初学一级) | 2019-12-05 17:54

@阿爆g:

所以说还是要看场景:
1.高并发
2.并行的多个耗时任务

效果上,再举一个例子,比如你的一台服务器配置很高,而IIS处理请求的能力是有限的;
用同步的的话,IIS最高可以响应1000个并发的时候,最多只能利用到50%的服务器处理能力;
而用异步的话,就可以利用到80%的服务器处理能力,去响应1500个并发;

支持(0) 反对(0) 码农搞事情 | 园豆:20 (初学一级) | 2019-12-05 18:07
0

首先 搞清楚异步的实现原理,楼上的都知道是系统的线程;

而使用 async和await 是更加高级的封装,不但简化了写法,而且注意这里不是Thread,而是Task;

而Task不等于Thread,所以反对了Dudu的一刀切说增加开销的说法 —— 不一定,如果线程池中的Thread没有被销毁,顺便拿来用,这种基本就算不得增加开销(因为可能Thread销毁比继续用  开销更大都说不定)。

传说的不一定是对的,异步是给你创造了线程池,但是你要相信IIS等等Server一定不会弱鸡到 过程不是Worker池(一般并发通讯都这么写,就不再称线程池了,差不多就是这个概念)模式,你应该知道IIS中有个线程设置的参数 —— 很明显你应该根据cpu及其虚拟化情况 以及 自己的应用(短时的多并发的和长时多运算的设置肯定不同)来设定,所以勿需过多担心 和 过多相信传言。

对于这种理解,我还是通常说法:你可以试试从Tcp构建HttpServer+MVC,你就明白了。

微软的封装和简化,对于进阶阶段,有时候务必去看看它的源码,就比如一个简单DbConnection,你在随便使用的时候觉得速度还不错,实际上你如果真正从通信连接对比,你才会知道比如Tcp你是不能当DbConnection那么玩的,那只是微软用空间换了时间,所以DbConnection可以随便玩,而真正的通信根本不会那么玩。

花飘水流兮 | 园豆:13560 (专家六级) | 2019-12-06 02:26
0

你要这样思考,一段业务代码A要是从执行到真正的得到执行后的结果,假如需要10秒。代码A完全不改任何code,不管使用什么奇淫巧技,10秒的耗时是很难提升到只要1秒的,除非硬件的提升。异步也不行,异步只是把执行权从线程B交给其他的线程C。线程C执行代码A仍然要10秒,免不了的。就算返回void,执行耗时也是10秒。只是这个转交的过程执行是极快的。线程A可以再次执行后续的任何代码。要是转交以后线程B不需要从线程C的代码A得到其执行结果,那么线程B就无需等待得到执行结果,要是一等待,那么10秒的耗时就反应到了线程B上了。

无尽折磨 | 园豆:204 (菜鸟二级) | 2021-08-30 20:41
0

实际上是的,单从一个异步来说,肯定是异步的效率低于同步的。原因很简单,async、await仅仅是语法糖,实际上编译器会对我们的代码做二次加工,例如:

一个简单的async、await,编译器会自动生成一个名称为<Run>d__1的类,然后创建该对象,赋值,创建状态机等等。这一系列操作,每一行都是消耗。

所以,一个异步方法的执行效率,肯定是低于同步执行的。

那问题来了,为什么大家都说异步能提高效率呢?

这里我以做饭举例说明。

假如,一个人想要完成做饭任务,那么他需要先买菜(30分钟),然后洗菜(10分钟),切菜(10分钟),炒菜(10分钟),最后出锅(1分钟)。

那么以同步的思想来做,那必然是要花费30+10+10+10+1=61分钟。在这期间你什么都不能做,因为你是同步,在你打算要做饭的那一刻起,你就得花费61分钟去完成这件事。

那要是异步呢?首先,买菜,不需要你亲自去买,你叫个外卖小哥直接送到家,那么这半小时你可能只需要花费2分钟和外卖沟通,然后你可以玩会游戏,或者扫个地,然后洗菜,切菜正常操作,然后炒菜的时候,你也不用一直翻炒,翻一会,就得焖一会,然后你又可以看看短视频。

从时间角度来说,确实是花费的更多了一些,因为你叫外卖,多花了2分钟,外卖小哥帮你买,他也得用30分钟,然后在炒菜的时候看短视频,可能也会多花1分钟,所以整体来说,花费的时间是2+30+10+10+10+1+1=64分钟。

但是,在这64分钟期间,你还扫了地,还看了短视频,甚至还能做其他事。总之,你过得很充实。

甚至来说,假如你想吃两个菜,那么按照同步的思想,你又得花61分钟。

而异步则不然,你可以同时打两个外卖电话,然后用两个锅炒,效率肯定杠杠的。

说到这里,你可能明白了,这个人,实际上就是一个线程。同步异步效率问题,一目了然。可是聪明的你又会问,一般我们的家庭(程序)都是多个人(多线程)的啊,我为什么不再雇一个人(开一个线程)呢?这样同样是61分钟,做两个菜,不香吗?

可问题是,人不是随便加的,一个人两个人还能说的过去,你要是想吃满汉全席,那不得有上百个人。而且,即使有上百人,实际上他们的工作也不是满载的,有的人炒两下,就盯着锅(线程阻塞),时间不是都浪费了。而且,总管(内核)左右吆喝调度人实际上也很累。

所以,让一个人(线程)不闲,就是异步最终的目标。

所以,异步并不能提高算力,只能榨干cpu。

若汝棋茗 | 园豆:202 (菜鸟二级) | 2023-08-22 15:10
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册