在mvc5以及.net4.5下,看到异步会用的比较多。也看到csdn上有些大佬写的代码都会用到。对于vs来说,其创建的默认项目也是基于await和asyc的。比如这样的代码:
[ResponseType(typeof(MW_Goods))]
public async Task<IHttpActionResult> GetMW_Goods(string id)
{
MW_Goods mw_goods = await db.MW_Goods.FindAsync(id);
if (mw_goods == null)
{
return NotFound();
}
return Ok(mw_goods);
}
但对于我来说,我始终觉得,如果在没有必要用异步的地方使用异步并没有必要。所以我想搞清楚,到底哪些场景下,使用异步真的可以带来帮助?
我们先假设代码结构,代码简单实现为同步(或异步)的Controller + Service的结构,即控制器的一个方法,调用服务的一个方法完成一个请求。Controller 的转发是CPU操作,Service层的执行一般是数据库(IO)操作。这里引入了有IO的环节,也是一般情况下认为异步能够发挥作用的场景。我们就假设Controller层100%CPU运算,Service层100%IO运算。
我们再以web应用为例,讲讲最常用的场景。先看iis的机制,我们知道,对于iis服务器,在并发执行客户请求时,是有排队机制的。假设iis同一时刻能启动100个线程并发执行请求,而请求最大队列为1000,那么后900个请求将被压入队列。
假设1个请求执行完需要200ms,因为线程并发数是100,所以1000个请求执行完毕,就需要200 * (1000 / 100) = 2000ms。这是在服务端不做任何异步处理的情况下的结果。
那么异步能带来性能的提升吗?先引入两个假设:
这里要引入两个假设:
1、假设1:假设单个请求的200ms时间中,20ms用于路由转发,180ms用于服务执行,即1:9的时间比
2、假设2:假设Service方法内部没有实现异步的需求,这是大多数的情况,即一般一个service方法是一个整体事务,内部不存在可以并发执行的多个部分
再来看几种情况:
1、当前服务器不存在瓶颈。即用户并发请求数在100以下。此时请求总是立即被处理,不会排队,那么用户的请求执行始终还是200ms,性能没有提升。
2、当前服务器存在排队。假设持续的会有900个请求在排队,100个请求在执行。那么:
使用异步前:第1001个请求需要等待 200 * (1000 / 100) = 2000ms才会被执行,执行完成总时间是:2200ms
使用异步后:直觉上感觉应该是不能提高性能的。可以做个计算。
第1001个请求需要等待 20 * (1000 / 100) = 200ms 会被开始处理,但此时处理结果还未返回;那么Service层执行IO需要多少时间呢?假设一台服务器的单位时间的IO能力是固定的,那么IO能力计算为:100个线程并发需要执行180ms,那么理论上1个线程执行需要耗费IO资源1.8ms。那么第1001个线程开始执行需要等待的时间是,1.8 * 1000 = 1800ms,加上之前的200ms,刚好是2000ms,再加上单个线程执行的总时间,第1001个线程执行完,也需要2200ms。
依据以上分析,我们是不是可以得出结论,对于客户请求的响应性能:
1、简单的异步化改造,不管是服务器是否处于存在瓶颈的状态,都不能提高性能,反而因为异步增加了线程间切换的成本,性能还会有所下降。所谓简单的异步化改造,就是controller异步化 + service的单一化异步(即内部不包含多个IO相关的异步方法)
2、必须对sevice层的某个方法做内部多异步方法的改造,才有可能提升性能。而这要做到以及做好,并不容易。你需要:
(1)明确这个方法是允许做异步化改造的。但往往一个service方法,它不应该是异步的,即它很可能是前后相互依赖。依据我的经验,我的应用场景95%以上都是后面的代码要依赖前面的读取结果,无法异步化。
(2)异步化改造后,可能一个方法要被拆成多个方法,这给系统带来了复杂性。但这一点我还不确定,因为我没怎么实践过。可能Task类能解决这个问题,使一个方法内多段代码异步执行,但我想这对编程能力的要求,应该不低,普通程序员可能容易出错。
基于以上分析,我的疑问是:
如果异步真正能带来性能提升的只是所有业务场景中的5%,那还有必要将系统整体改造为异步吗?这带来的好处,和投入的精力,以及带来的复杂性,异步化线程切换的开销相比,是不是不值得了?
我个人更倾向于系统整体仍然保持同步的处理代码,然后根据系统的运行情况,只针对瓶颈真的存在的部分,进行分析和异步化,这是不是更好的方式?这既保持了系统架构的简洁性,开发的简单性,运维的稳定性,也能在异步化真正能带来效果的业务点上进行真正有效的异步化改造?
请多多指教。