计算机底层运转机制:多核、缓存、CPU、CU、ALU、Cache
现代CPU《编译型语言与解释型语言如何在计算机底层运行》中提到,计算机依靠编译器将源代码(编译型编程代码:C之类)编译成机器码执行,准确说,就是用CPU执行。冯 诺伊曼架构冯⋅\cdot⋅诺伊曼(1945)提出当前计算机的主流架构,包含以下三大部分:CPU(Central Processing Unit):包含控制单元(Control Unit)、逻辑运算单元(Arithme...
-
现代CPU
《编译型语言与解释型语言如何在计算机底层运行》中提到,计算机依靠编译器将
源代码
(编译型编程代码:C之类)编译成机器码
执行,准确说,就是用CPU执行。 -
冯 诺伊曼架构
冯 ⋅ \cdot ⋅诺伊曼(
1945
)提出当前计算机的主流架构,包含以下三大部分: -
概念解析
-
CPU(Central Processing Unit)
CPU
,中央处理器,负责执行用户和操作系统下发的指令
。此处指令
,是以01二进制形式组织的机器码
,在物理底层,01用来控制高低电位。 -
指令集
除了加减指令,CPU的电路还要实现很多其他指令:内存读取、逻辑判断。
指令控制物理电位,不同电路厂家电路设计不同,则电路上所能进行的二进制码就不同。
某类CPU
能支持一种指令集
(instruction set architechture
),指令集
相当于一种设计图纸,规定了一种CPU架构
实现哪些指令。常见的指令集有:
x86
:常见ARM
:常见MIPS
SPARC
:龙芯Power
:IBM
小型机
有了指令集:
- 硬件开发人员只需要关心如何设计电路;
- 软件开发人员只关心如何使用01机器码实现软件功能;
-
-
单核CPU的架构
前面图片展示了冯 ⋅ \cdot ⋅诺伊曼计算机架构,下图展示了一个
单核CPU
的架构:其中包含:
-
Control Unit
(CU
):控制单元,协调管理; -
Arithmetic Logic Unit
(ALU
):数学逻辑单元,接受控制单元CU
的命令,负责进行加减乘、与或非运算。 -
Register
:ALU
是负责计算逻辑,具体计算的数据是存放在寄存器(Register
,几KB大小)中,寄存器以极高的速度(<1纳秒
)与CU
和ALU
交互。寄存器中的数据是临时寄存的,这些数据和指令会被
ALU
和CU
拿来立即进行计算,如果寄存器中没有CPU
想要的数据,CPU
会去内存或硬盘中读取。 -
BUS
:总线,如果寄存器中没有CPU
需要的数据,CPU
会去内存或硬盘中读取,这个读取内存或其他设备数据的过程,是通过Bus
(总线)来实现,计算机中有多条总线。
举例说明计算过程:
对于一个加法运算,计算机需要知道两个问题:
- 本次所执行的是哪个指令;
- 该指令的执行对象是什么;
具体过程:
- 控制单元
CU
先取指令(Fetch)
; 指令译码(Decode)
解析出要执行什么指令;- 确认指令是对哪些数据(
操作数Operand
)进行操作; - 将
操作数
从主存
加载到寄存器
中; - ALU
执行指令(Execute)
; - 结果写回
Store
;
-
-
存储金字塔
计算机的速度瓶颈,已经变成了
超高速的CPU运算速度
(纳秒级别)与落后的数据读取速度
(百纳秒)之间的矛盾。CPU计算完成后,要闲置几十倍的时间,等待存取。
CPU的
寄存器
存取速度极快,但是造价成本太高,发热量大,不能被大量采用。通常,CPU的寄存器只有几KB
;L1 Cache
和L2 Cache
一般设计在CPU
上,访问延迟在几~几十纳秒
内;主存
的访问延迟在百纳秒
内;速度越快,意味着成本越高。所以硬件设计是在现有技术水平、期望计算速度、成本、散热等因素之间所做的
trade-off
。 -
多核
当单个
CPU
主频超过一定范围后,CPU
成本和散热成了很大的问题,主频很难突破10GHz
。为了获得更快的计算速度和更好的性能,芯片设计者决定绕过主频,采用人海战术,在一块
CPU
中增加多个核心(Core
)。一个核心是一个可以运行指令的独立单元,它包含了
ALU
和寄存器
,并配备L1
和L2 Cache
。多个核心共享L3 Cache
。上图是一个多核处理器电路图。下图是多个多核处理器:
服务器可以支持多个处理器(CPU),支持单个CPU的服务器称为单路服务器;支持两个CPU的服务器称为双路服务器。上图是
Intel
的四路架构,系统支持四个CPU,假如每块CPU
内有8个核心
,系统可对外提供32核
计算能力。 -
线程与进程
前面的知识都是硬件层面,而线程和进程则是操作系统控制这些硬件而创造的软件概念。
在多核架构出现之前,CPU在特定时刻只能执行某个程序,无法并行。
因为CPU的处理速度是纳秒级的,在单核时代,为了同时处理多项任务,只能以多线程,CPU切换不同的线程任务。
-
线程安全问题
用两个线程针对
i = i + 1
进行操作,理论希望是变量被加了两次。而实际情况是:- 两个线程相隔时间短,加上缓存机制,计算的过程和临时结果还在寄存器和L1缓存,尚未写入主存;
- 线程B读到的还是主存上比较老的数据;
就导致出现了数据不一致的情况,就是所谓的线程安全问题。
所以,
Python
就通过添加GIL
锁来保证线程安全。 -
References
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)