Python高性能编程(二)基本计算机系统
基本的计算机可以看做由三个部分组成:计算单元、存储单元和通信单元。一个基本的计算机系统硬件组成如下图:
4-计算机系统硬件组成.png计算单元
性能指标
计算单元是计算机的核心组件,它的作用是将接收到的比特流进行处理和转换之后输出。
计算机的主要计算单元为CPU和GPU(上图中图形适配器的核心)。
计算单元的性能指标主要有两个:
- IPC(Instruction Per Clock):即每一时钟周期内能执行多少条指令。提高IPC对计算单元的矢量计算能力有相当程度的影响;
- 时钟频率:即每秒能完成多少个时钟周期(通常我们说的CPU主频多少GHz指的就是时钟频率)。时钟周期是计算机中最基本的时间单位,在一个时钟周期内,计算单元仅能完成一个最基本的动作(即取指令、存储器读、存储器写等)。提高时钟频率可以提高该计算单元上所有程序的运行速度。
通常来说IPC和时钟频率是相互竞争的关系,想要同时提高二者需要工艺的突破。相较于CPU,GPU的IPC和时钟频率都很高,但是它的计算性能受到较慢的总线传输速度的制约。
加速手段
在物理上,提高计算单元性能的方式就是提高单位面积芯片上晶体管的数量,但是目前晶体管的大小已经接近物理极限,在这个基础上再进行提高就需要直接操作原子排列的能力了,因此摩尔定律也快到了尽头。如果不考虑将来计算机系统的整体颠覆,如量子计算机体系,我们现在用来加速计算的手段主要有以下几种:
- 超线程技术:通过虚拟硬件,高效利用计算单元的空余能力。简单来说就是在计算单元执行某个任务的间隙里,通过聪明的调度方案,插入另一个大小合适的任务;如果调度得当,能够提升一个CPU核心20-30%的性能。
- 乱序执行:如果编译器检查出一个程序的某一部分和前面的操作无关,那么这时候程序的两部分可以以任意顺序交错执行甚至同时执行。乱序执行就是将这两部分或者多部分进行调度安排,在一些指令被阻塞(例如网络下载或者内存访问)时,执行另一些程序,从而提高资源利用率。
- 多核架构:如果我们为计算单元如CPU增加更多计算核心,那么理所当然能够提高计算单元的性能,我们常看到的四核八核计算机就是出于这种考虑。但是单纯增加更多核心并不一定能够提高程序运行的速度,这是由阿姆达尔定律(Amdahl's law)决定的。也就是说,一个可以在多核上执行的程序如果有一部分必须要在单核上运行,那么这一部分就会成为瓶颈,导致无法通过增加核心提高这个程序的运行速度。
存储单元
性能指标
存储单元的主要作用就是保存比特信息。无论是程序中的变量、一张图片还是一本小说,在存储单元中都是以一系列01的形式保存的。计算机系统中的典型存储单元包括寄存器、RAM、硬盘以及远程存储。
存储单元的性能指标主要有两个:
- 读写速度:读写速度和读写的方式相关,对于大多数存储单元,一次性读取大块连续存储的内容,要比多次读写多个不连续的数据块要快得多。
- 延时:即设备为了查找到需要读写的数据位置需要的时间。这和设备的存储方式直接相关,例如机械硬盘要靠移动磁头并旋转硬盘到一定速度来查找数据,这会导致较高延时。而固态硬盘在这方面的表现就好的多。
加速手段
为了加快存储单元中的读写,很多系统都实现了层次存储:数据开始存放在本地或者远程存储中,然后其中一个子集进入主存,高速缓存则再从主存中读入一个小部分,最终将数据读入寄存器中。
下图展示了一个存储器层次结构示例:
5-计算机存储器层次结构.png通信单元
性能指标
通信单元通常指的是各种总线。对于总线,主要的性能指标有两个:
- 总线带宽:也就是这条总线一次能够传输多少数据。我们在读取的过程中,总是从存储中读取一块输入,然后一次或者分批通过总线进行传输。如果总线带宽较大,我们就能够一次性传输较大的数据块。
- 总线频率:也就是这条总线每秒能够传输多少次数据。当总线频率较高时,方便我们进行多次的读取,这对于需要经常随机读取内存的代码较为有利。
总线带宽和频率是由物理布局决定的:芯片之间的物理链路长度较短时,传输速度就会变快。而物理链路的数量则决定了带宽。
加速手段
如前所述,总线的传输速度主要取决于物理布局,因此主要是通过精妙的复杂设计,来对总线布局进行优化。我们的CPU片内总线连接就经历了从早期的星形连接进化到环形总线到Mesh网络的过程。