依据冯·诺依曼体系结构,主要包含五大基本单元
- 运算器
- 控制器
- 存储器
- 输入设备
- 输出设备
其中,运算器和控制器通常被集成在一起,就是中央处理器
CPU
CPU是计算机的核心,负责执行程序中的指令和处理数据。它内部主要由两大单元构成
- 控制器
- 功能:它是整个计算机的指挥中心。类似于交通警察,它不直接处理数据,而是负责协调和控制其他所有部件的工作
- 工作流程:从内存中读取指令 -> 解码指令 -> 根据指令的含义,向其他部件(如运算器、内存、输入输出设备)发出相应的控制信号,指挥它们完成操作
- 运算器
- 功能:负责执行所有的算术运算和逻辑运算。它是真正”干活“的计算单元
- 核心部件:
- 算术逻辑单元:执行加、减、乘、除等算术运算和与、或、非、比较等逻辑运算
- 寄存器:CPU内部极快但容量很小的存储单元,用于临时存放正在被处理的指令和数据
CPU的逻辑架构
CPU的根本任务是执行指令。这个工作可以分解为一个循环往复的过程,即指令周期
CPU核心部件
控制单元(CU)
CU是CPU的神经中枢,它自己不执行计算,而是负责协调和管理整个CPU的工作
- 功能:
- 指令获取:从程序计数器(PC)中获取下一条指令的地址,并向内存(实际上的L1缓存)发出请求,获取该指令
- 指令译码:取回的指令被放入指令寄存器(IR)。通过CU解析这条二进制指令的含义(例如,这是一次加法运算,操作数在哪个寄存器等)
- 发出控制信号:根据译码结果,CU会激活一系列精密的控制信号线,这些信号像指挥棒一样,控制数据在寄存器、ALU和总线之间的流动。(例如,它会告诉ALU执行加法而不是减法,告诉寄存器文件该读取哪个寄存器,等等)
- 关键组件
- 程序计数器:一个非常重要的专用寄存器,永远指向下一条要执行的的指令的地址。正常情况下,它每执行完一条指令就自动+1;遇到跳转指令(如if/else、循环)时,则会被填入新的目标地址
- 指令寄存器:用于存放当前正在执行的指令
算术逻辑单元(ALU)
ALU是CPU中真正进行”计算“的地方,所有数学和逻辑运算都在这里完成- 功能:
- 算术运算:执行加、减、乘、除等基本数学运算。值得注意的是,现代CPU的乘法器和除法器通常是特别优化的电路,但最核心的加法器是ALU的基础
- 逻辑运算:执行与、或、非、异或等逻辑操作
- 位运算:执行位移、位旋转等操作
- 工作原理:
- ALU从寄存器或内部缓存中获取输入数据(操作数)
- 根据CU发来的控制信号(例如,”执行加法“),选择相应的计算电路(如加法器)进行运算
- 将计算结果输出,并设置标志寄存器中的状态位
- 关键组件:
- 标志寄存器:一组特殊的位(触发器),用于记录ALU上一次运算的结果状态。常见的标志位有:
- 零标志:结果是否为0
- 进位标志:运算是否产生了进位或借位
- 溢出标志:结果是否超出了数据表示的范围
- 符号标志:结果的符号是正还是负
- 这些标志位对于后续的条件跳转指令(如”如果相等则跳转“)至关重要
- 标志寄存器:一组特殊的位(触发器),用于记录ALU上一次运算的结果状态。常见的标志位有:
寄存器文件
寄存器是CPU内部速度最快、延迟最低的存储单元,由触发器构成,用于临时存放即刻需要使用的数据、地址或指令
- 特点:
- 容量很小(x86-64架构的CPU通常只有16各通用寄存器左右),但速度极快,访问速度是纳秒级,远超内存
- 它们与ALU和CU直接相连,是数据处理的”第一现场“
- 主要类型:
- 通用寄存器:用于存放数据和地址,程序员或编译器可以灵活使用。例如,在x86-64架构中,有RAX, RBX, RCX, RDX等。RAX常作为累加器,是许多算术运算的默认目标寄存器
- 专用寄存器
- 程序计数器:如上所述,属于控制器,但本身也是一个寄存器
- 指令寄存器:如上所述,数据控制器
- 堆栈指针:用于管理函数调用时的堆栈
- 基址指针:也用于堆栈帧的管理
缓存
虽然缓存通常被视为一个独立的层级,但在现代CPU设计中,它已被集成在每个核心内部,是其高效运作不可或缺的一部分
- 作用:解决CPU超高运算速度与相对缓慢的内存速度之间的巨大矛盾
- 层级:
- L1缓存:速度最快,容量最小(通常为几十KB)。被集成在CPU核心内部。每个核心都有自己独立的L1指令缓存和数据缓存
- L2缓存:速度比L1慢,但容量更大(通常为几百KB到1MB)。通常也是每个核心独享。
- L3缓存:速度最慢,但容量最大(通常为几十MB),由所有CPU核心共享
- 工作原则:基于”局部性原理“,将内存中近期可能被用到的数据和指令复制到缓存中。当CPU需要数据时,它首先在L1中寻找,如果找不到(缓存未命中),则依次去L2、L3和主内存中寻找
核心工作流程:指令周期
指令周期通常包含四个主要步骤:
- 取指
- 控制器根据程序计数器(一个特殊的寄存器,存放下一条指令的地址)的值,从内存中读取下一条指令
- 取出的指令被放入指令寄存器中
- 译码
- 控制器分析指令寄存器中的指令,弄清楚这条指令要求CPU做什么(是加法?是从内存加载数据?还是跳转到另一个地址?)
- 这个过程就是把二进制机器码翻译成CPU内部能理解的控制信号
- 执行
- 控制器根据译码结果,向相关的部件发出控制信号
- 如果指令是计算类的(如加法),控制器会命令运算器工作,从寄存器或内存中取出操作数,完成计算
- 如果指令是数据传送类的(如从内存读取数据),控制器会命令内存总线和寄存器进行数据传输
- 写回
- 将执行阶段得到的结果存入指定的位置,比如一个寄存器或者内存中
- 完成后,程序计数器的值会自动更新,指向下一条要执行的指令地址,然后循环重新开始
CPU的物理实现
存储器
存储器用于存放程序和数据。根据其速度、容量和与CPU的距离,可分为多个层次
主存储器
- 就是常说的内存
- 特点:速度快,但断电后数据会丢失。CPU可以直接与之交换数据
- 作用:临时存放当前正在运行的程序和需要处理的数据。他是CPU与外部存储(如硬盘)之间的桥梁。
辅助存储器
- 就是常说的外存或硬盘,包括机械硬盘、固态硬盘、U盘等
- 特点:容量大、断电后数据不丢失,但速度比内存慢得多
- 作用:长期保存大量的程序、文档、照片、视频等数据
输入/输出设备
- 输入设备负责将外部的信息(数据或指令)转换成计算机能识别的形式,送入计算机内部
- 输出设备负责将计算机处理后的结果,转换成人能理解的形式(如文字、图像、声音)呈现出来
##总线 以上所有部件并非孤立存在,它们需要通过系统总线链接起来。总线负责在部件之间传输数据、地址和控制信号
- 数据总线:传输实际的数据
- 地址总线:指定数据在内存或I/O设备中的位置
- 控制总线:传输控制器发出的控制信号
存储层次
总结工作流程
以计算“1+2”的例子\
- 输入:通过键盘输入“1+2”这个指令
- 存储与传输:指令通过总线被送入内存中暂存
- 控制与执行:
- 控制器从内存中读取“1+2”这个指令,并进行解码
- 控制器指挥运算器进行加法运算
- 控制器从内存中将数据“1”和“2”取出来,送入运算器
- 运算器执行1+2的运算,得到结果“3”
- 输出:运算结果“3”被送回内存,然后通过总线传送给显示器,最终看到屏幕上显示3
局部性原理
局部性原理描述了程序在执行时访问数据(数据访问)和指令(指令访问)的一种可预测的模式。它指出,在短时间内,程序更倾向于重复访问它最近使用过的数据或指令,或者访问这些数据/指令附近的数据
这个原理是计算机体系结构中几乎所有缓存层次(CPU缓存、内存、磁盘缓存等)得以有效工作的理论基础。正是因为存在局部性,我们提前将”可能要用到的数据“拿到更快的存储设备中才是有意义的
局部性原理主要分为两类:
时间局部性
- 核心思想:如果一个数据/指令被访问了,那么它在不久的将来很可能会被再次访问
- 在程序中的体现
- 循环:循环体内的指令会被反复执行
for (int i = 0; i < 1000; i++)
{
sum += i; // 变量 sum 和 i 在每次循环中都被重复访问 -> 强时间局部性
}
- 函数调用:一个被频繁调用的函数,其指令代码会被反复执行
- 计数器、累加器:这些变量会被频繁读写
缓存的作用:基于时间局部性,缓存会将最近访问过的数据保留起来,但CPU再次需要时,直接可以从高速缓存中获取,而无需访问更慢的内存
空间局部性
- 核心思想:如果一个数据/指令被访问了,那么它在存储空间中相邻的数据/指令也很快可能被访问
- 在程序中的体现:
- 顺序执行的指令:程序中的指令在内存中通常是连续存放的,并被顺序执行(除了分支和跳转)
- 数组或集合的遍历:访问数组的连续元素
int array[100];
for (int i = 0; i < 100; i++)
{
array[i] = i; // 访问 array[i] 后, 接下来很可能会访问 array[i+1] -> 强空间局部性
}
- 对象的字段:一个对象 的多个字段在内存中通常会分配在一起。访问一个字段后,很可能很快会访问统一对象的另一个字段
缓存的作用:基于空间局部性,当CPU从内存中读取一个数据时,缓存不会只读取这一个数据,而是会读取一个连续的数据块(称为缓存行),并将其存入缓存。这样,当CPU需要下一个相邻的数据时,它已经存在于高速缓存中了
局部性原理的实际应用与重要性
- CPU缓存:这是最直接的应用。L1, L2, L3缓存的存在就是为了利用局部性原理。缓存行(通常是64字节)的设计就是空间局部性的完美体现
- 内存分页与虚拟内存:操作系统将程序的内存划分为”页“。当程序访问一个不在物理内存中的页时,操作系统会从磁盘调入该页。它不会只调入一个字节,而是调入整个页面(如4KB),这利用了空间局部性。同时,”工作集“概念就是指程序在某段时间内频繁访问的页面集合,这利用了时间局部性
- 磁盘缓存:操作系统会将最近访问的磁盘扇区内容缓存在内存中,以加速后续的读取。
- 数据库优化:数据库会缓存频繁执行的查询结果(时间局部性),并且在从磁盘读取数据时,会预读相邻的数据页到缓冲池中(空间局部性)
- 编程指导原则:理解局部性原理可以帮助程序员写出更高效的代码
- 高效示例:遍历一个多维数组时,应遵循”行优先“的顺序(在C/C++、Python等语言中),因为内存是线性分布的,行中的元素在内存中是连续的
// 好的写法:空间局部性好
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
array[i][j] = ... // 按行访问
}
}
- 低效示例:”列优先“遍历会导致频繁跳跃内存访问,破坏空间局部性,造成大量缓存未命中,性能急剧下降
// 差的写法:空间局部性差
for (int j = 0; j < M; j++)
{
for (int i = 0; i < N; i++)
{
array[i][j] = ... // 按列访问,每次访问都跳很远
}
}
总结
局部性原理是一个简单而强大的观察结果:程序的行为在时间和空阿金上往往是可预测和集中的
- 时间局部性:利用”最近用过的,很可能再用“
- 空间局部性:利用”用了这个,很可能用它旁边的“
正是基于这个原理,计算机系统通过构建多层次的存储结构(寄存器 -> 缓存 -> 内存 -> 磁盘),并配合预取、缓存等策略,成功地掩盖了不同存储介质之间巨大的速度差异,从而实现了今天所见的高性能计算