这个代码中,userService获取值如果是直接从内存获取,那么它并不会给带来性能提升,还有可能带来性能损耗,如果它是从redis或数据库获取,那么会得到一定的提升。
异步是一种很高效的操作,能够尽力榨干机器的性能,明白它的原理就很简单了。
比如现在有十个请求,每个请求分成三个阶段处理,初始化10ms,读取数据库10ms,运算10ms。
假如有一台服务器,一次只能处理1个请求,那么同时来十个请求,排入队列,1号请求要等到回复要30毫秒,2号回复要等1号完成再进行,那就需要60ms,以此类推,需要300毫秒完成。
如果是异步,第一个请求进入读取数据库时,CPU就空闲出来了,那么第二个请求的运算就可以开始了。
可以注意到当第一个请求第一阶段运算完成,读数据库时,CPU已经空闲下来了,但是同步的话就只能让它空着。
如果采用异步,第一个请求30毫秒完成,第二个第40毫秒时就可以完成,第三个请求50ms…十个请求只需要120ms就可以完成。
可以看到,十个请求,120ms就处理ms了本来要300ms才能处理好的任务,时间节省了一半多。
nodejs单线程能够有极高的性能,也是通过异步来实现的。
性能的提升意味着你可以用更加便宜的硬件节省成本以及应对各种业务需要。
所以,异步的适用于充分利用资源空闲,反之,如果是不会出现资源空闲的任务,比如上述场景的十个请求都仅仅是读取数据库的话,是毫无意义的。
然后又会有疑问了,通常的web服务器,它同时能处理多个请求,异步是否还是需要的?
设想一个场景,同时来了一万个请求,而服务器比如在Java中直接开同步线程,如果开上几千个就会不堪重负,并且会占用相当大的内存空间,并且显然这几千个线程仅仅是挤出来了计算空间,而对于共享资源比如读写数据库,线程需要进行互相加锁处理。
如果有每个进程,需要先读写10ms数据库,然后计算10ms,再读写数据库10ms,那么你将需要让它持有数据库资源高达30ms,其中有10ms只能眼睁睁看着,一万个请求将浪费10万ms用于等待。
如果能让线程们能够自己切换,它们就像帝国时代里的工人们,砍树的也能采石头,也能造房子,这个问题就能解决。
将任务进行分割,计算的任务,读数据库的任务,进行分离,然后一堆线程轮流负责专门读写数据库,一堆线程轮流专门负责计算,哪里有空闲时,闲的一堆线程过去负责其他工作。
听起来是不是很耳熟,这就是使用iocp或是epoll实现高性能处理的关键,写这些东西很繁琐,调度听起来也有点复杂,放到十多年前,会用这些的,光是跟人口沫横飞都可以吹上个大半天,而且大多数人即使知道了原理,也很难将它们运用好。
到现在,这些完全不用操心了,只需要简单的async与await,调调下线程池参数,必要时再用用自旋锁,遵循好规范,轻易就可以实现高性能方案。