原创

性能的基本理解:为什么顺序执行一个操作,要比并发执行效率更低?tps更差?

暴雨梨花枪
2022-08-27 17:10 18687人阅读

最近一个客户提问说,我的系统顺序执行不是也很快嘛,为什么要并发来执行呢?

这个问题初看很简单,我仔细想了一下,其实不太容易回答,尤其是现在高级语言越来越多,导致开发人员对系统的理解比较困难。其实就是对系统的性能理解存在很多偏差。

第一个问题,程序执行时间,是如何来计算的?我们知道,当前的系统几乎都是冯诺依曼架构的,它顺序的执行指令(也就是程序编译完成的结果),来完成一个一个的功能。每一条指令,执行的时候,都包含了几个时钟周期。比如,一个指令可能包含1个时钟周期,也可能包含多个。所谓时钟,就是我们经常看到的,你的电脑的主频,其实是cpu主频,是多少G的,就是一秒钟有多少个时钟周期。假设你的代码要执行5万条指令,平均每条指令有2个时钟周期,那么执行完成这一段代码,就需要10万个时钟周期,再根据主频,我们就能够知道,需要多少时间了。

第二个问题,为什么并发执行速度更快?其实有几个原因:1)我们的cpu是多内核多线程的。每个线程可以独立执行一个指令序列。比如16线程的cpu,可以同时执行16段代码,如果你的代码只允许单个执行,那么只使用了1个线程,其他的15个在“休息”,当然不够快。如果你让它同时跑16并发,肯定能够得到更快的执行速度。2)操作系统调度。我们知道,当执行代码的时候,比如你遇到一个通讯代码,要从一个“句柄”中读取信息,那么这个程序就会陷入等待状态,操作系统就会“挂起”它,直到这个信息发过来,触发了一个“中断”,来唤醒了这个代码,让它继续执行。当代码被挂起,其实操作系统就可以安排其他的程序进来执行。所以,虽然你的cpu有16线程,但是它可以执行更多的并发。

第三个问题,为什么有的代码,看起来长度差不多,但是却很慢?我们知道,程序代码如果使用了“系统调用”,那么其实这个功能是操作系统提供的,会进入操作系统的另外一个状态,导致执行了一大堆你看不到的代码。如果你的代码没有系统调用,原则上可以比使用系统调用的代码跑的更快。举个例子,比如你的代码用到了动态内存,这个内存从哪里来呢?从操作系统的“堆”来,那么就要去操作系统的“堆”申请一片内存。如果你想让它很快,那么你可以开一片大的内存在本程序内,一般使用局部变量。局部变量开在哪里?一般在“栈”里面。你会发现,性能提升了非常多。

以上,我们解释了,程序执行占用cpu和时间的问题,以及为什么并发执行的代码往往会效率更高。当然,如果你的并发设置的过高,也会起反作用:由于cpu线程的频繁调度导致性能下降。


下面我们说一下,如何优化代码。首先,要优化单个代码的执行速度,就是缩短执行时间。比如,一段代码原来执行一次,需要2秒。如果你优化到0.2秒(就是200毫秒),那么速度就提升了10倍。代码优化,最主要的就是算法,减少指令执行条数,避免循环嵌套、甚至循环展开。技术手段很多,有兴趣可以自己搜索研究。

当单个的代码执行速度提升,我们就可以通过性能测试工具(比如泽众软件的performanceRunner)来并发执行,看看在大并发之下,会不会由于资源冲突或者竞争导致的性能急速下降。单独执行速度快的代码,也可能在一定并发到达之后,忽然慢下来的。比如,你的数据库没有索引。

这篇文章的目的是帮助我们理解,什么是性能,从cpu和指令的角度看,如何看待执行速度。

©著作权归作者所有:来自Alltesting产品社区作者暴雨梨花枪的作品,如需转载,请注明出处,否则将追究法律责任

沪ICP备07036474号2003-2022 版权所有 上海泽众软件科技有限公司 Shanghai ZeZhong Software Co.,Ltd.