1、冯诺依曼体系(Von Neumann Architecture)
现代的计算机,
大多遵守
冯诺依曼体系结构
- CPU 中央处理器: 进行算术运算和逻辑判断.
- 存储器: 分为外存和内存, 用于存储数据(使用二进制方式存储)
- 输入设备: 用户给计算机发号施令的设备.
- 输出设备: 计算机个用户汇报结果的设备.
针对存储空间:硬盘 >
内存
>> CPU
针对数据访问速度:CPU >> 内存
>
硬盘
认识计算机的祖师爷 -- 冯诺依曼
冯·诺依曼(John von Neumann,1903年12月28日-1957年2月8日), 美籍匈牙利数学家、计算机科学家、物理学家,是20世纪最重要的数学家之一。冯·诺依曼是布达佩斯大学数学博士,在现代计算机、博弈论、核武器和生化武器等领域内的科学全才之一,被后人称为“现代计算机之父”、“博弈论之父”.
2、CPU 基本工作流程
接下来,我们用一个从无到有的过程,一步步搭建一个
CPU
出来,希望大家可以借助这个过程,理解CPU、内存等计算机主要部件的工作原理。
2.1 逻辑门
电子开关
——
机械继电器
(Mechanical Relay)
通过电子开关,我们可以实现 1 位(bit) 的看似无用的逻辑运算,但至少它工作起来了,不是么。怎么使用电子开关组合出真正有用的逻辑组件,我们接来下会做进一步的学习了解。以后的真空管、晶体管的实质也是完成类似的工作,只是物理原理更加复杂。
2.2 门电路(Gate Circuit)
接下来,我们学习如何使用电子开关构建一些有用的部件 ——
门电路。可以实现
1
位
(bit)
的基本逻辑运算。
2.3 算术逻辑单元 ALU(Arithmetic & Logic Unit)
ALU 是计算机中进行算数、逻辑运算的核心部件,是计算机的数学大脑。接下来,我们用上一节构建的逻辑门来完成自己的一个 ALU
,去学习理解它的工作模式,以便作为我们进一步理解现代计算机工作原理的基石。
2.4 算术单元(Arithmetic Unit)
算数单元,负责计算机里的所有数字操作,比如四则运算,当然它能做的远远不止这些。接下来我们会带着大家实现一个 8 位(
bits
)的加法器(
adder
)来,以演示整个过程,其他的运算器就不再详细讲解了。
至此,一个 8 位(bits) 加法器就被我们从无到有制作了出来。算术单元支持的操作当然远不止这些,通过继续组合逻辑门,算数单元可以做到加减乘除甚至更多的算术运算,但一个加法器作为演示已经足够了。实际上,乘法器和除法器的制作难度是要高于加、减法器的。
2.5 逻辑单元(Logic Unit)
逻辑单元主要用来进行逻辑操作,最基本的操作就是 与、或、非操作,但不只是一位(bit)
数的比较。
2.6 ALU 符号
经过我们的努力,通过基本的逻辑门电路,我们一步步地做出了一个 8
位
(bits) ALU
,甚至比
Intel74181 还要强大,
Intel 74181
只是一个
4
位
(bits) ALU
(
😀
)
。当然现代的计算机中的
ALU
部件非常强大,复杂度远远超过了我们的想象,32
位 甚至
64
位基本已经普及全球了。但无论如何,再复杂的
ALU也是芯片工程师像我们这样,一层又一层,一步又一步地将其抽象出来的。ALU
是第一次将人类历史上的数学和逻辑学学科有机地结合起来,可以视为人类智慧发展的现代巅峰。
2.7 寄存器(Register) 和内存(RAM)
光有 ALU
还是远远不够的,我们无法为
ALU
提供存储的部件,所以接来下,我们利用门电路简单说明下存储的制作。注意,虽然图中没有明显的表示出来,但这些存储都是要求必须保持通电状态的,也就是这些存储都是易失的(volatile
)。
中间我们隐藏了一些实现细节,最后的效果就是:使能线置位时,输入为 1,保存 1;输入为 0,保存0。使能线不置位时,则写入无效。
我们可以利用门锁,构建我们需要的寄存器和内存。
内存的构建要比这个复杂一点,但基本原理一致。如此构建的内存被称为 RAM(Random Access Memory),可以支持 O(1) 时间复杂度访问任意位置的数据,这也就是我们数组下标访问操作是 O(1)的硬件支持。
期间,为了我们学习的聚焦性,我们隐藏了大量的实现细节,对于这部分知识感兴趣的同学可以在课后做深入的学习。
2.8 控制单元 CU(Control Unit)
我们现在有 ALU
、存储了,但这还是不足以让我们的计算机工作起来,我们需要有一个部件来指挥
ALU进行何种的运算,而这个部件就是控制单元(CU)。
关于 CU 如何由门电路从无到有搭建,我们就进行抽象了,只需要理解 CU 可以驱动 ALU 进行具体的计算工作即可。
2.9 指令(Instruction)
首先,我们先介绍下我们需要到的指令(instruction)
。所谓指令,即指导 CPU
进行工作的命令,主要有操作码
+
被操作数组成。其中操作码用来表示要做什么动作,被操作数是本条指令要操作的数据,可能是内存地址,也可能是寄存器编号等。指令本身也是一个数字,用二进制形式保存在内存的某个区域中。
2.10 CPU 的基本工作流程
接下来,我们演示指令运行的一个周期,希望同学们可以学习到其流程,并完成剩余指令的运行过程。
第一条指令的运行,其实没有用到我们之前制作的 ALU 部件,但这只是其中一些指令而已,大家尝试把剩余的 3 条指令自行运行一次,观察并理解这个过程。
我们来总结下执行周期经过哪些阶段:
当然,电子计算机中的 CPU 可不像我们刚才那样,靠自己来驱动这个周期的运转,而是靠背后一个时钟来进行周期驱动的。
时钟频率是个什么概念?? - 知乎 (zhihu.com)
最后,ALU + CU + 寄存器 + 时钟就组成了我们平时经常看到的一个词汇:中央处理器(Center Process Unit)简称 CPU。
2.11 小结
通过上述的章节,我们带领大家从基本的电子开关开始,一步步的搭建了一个CPU
和内存出来,虽然中间还是对很多过程和细节做了隐藏和抽象,但主要流程已经体现了出来
。然后我们把这一节中一些要点给大家做一个文字总结:
1. CPU
中的
PC
寄存器,是决定
CPU
要执行哪条指令的关键;
2.
指令是由 动作
+
操作对象组成
3. CPU
眼中只有指令,没有其他的概念
3、编程语言(Program Language)
这一节,我们借助上一节制作的 CPU
和 内存,来尝试还原下我们已经熟悉的编程语言,例如
Java
是如何和 CPU
指令对应起来的。
3.1 程序(Program)
所谓程序,就是一组指令以及这组指令要处理的数据。狭义上来说,程序对我们来说,通常表现为一组文件。
程序 =
指令
+
指令要处理的数据。
下面图给大家展示了 Altair 8800 计算机,是最早的一批微型电脑。用户需要控制开关,一个一个 bit 的将程序录入该电脑中。
3.2 编程语言发展
为了提升编程效率,最早创造了汇编语言的概念。其实汇编语言和机器语言(也就是指令)直接是完全一一对应的,只是相对于 0、
1
这些数字,发明了一些帮助人类记忆和理解的符号将其对应起来,也就是我们上面看到的类似 LOAD_A
、
LOAD_B
等。程序员完成编程之后,需要使用汇编器(
assembler
)将汇编语言翻译成机器语言。
虽然汇编降低了程序员的记忆成本,但要求程序还是必须掌握计算机硬件的所有知识,而且随着计算机厂商越来越多,一次编写的程序往往只适用于一类计算机。这个是远远不够的,所以更为高级的语言诞生了,高级语言屏蔽了硬件细节,让程序员可以站在更高的层面上思考自己的业务。这里以 C 语言为例,程序员完成程序的编写之后,需要使用编译器(compiler
)和连接器(
linker
)将程序翻译成汇编语言,再借助汇编器变成最终的机器语言。
借助封装的思想,我们学习编程变得越来越容易。不过有利则有弊,高度的抽象,导致很多的程序员把计算机视为一个黑箱,完全无法理解自己的程序是如何工作起来的,希望我们大家不要做这种程序员。
我们使用的 Java
语言相对于
C
语言更高级一点,但基本抽象原理上没有太大的差异,我们暂时就不展开说明了。
注意:高级语言的一条语句(Statement)往往对应很多条指令(Instruction)才能完成。
4、操作系统(Operating System)
操作系统是一组做计算机资源管理的软件的统称。目前常见的操作系统有:Windows
系列、
Unix
系列、Linux系列、
OSX
系列、
Android
系列、
iOS
系列、鸿蒙等
4.1 操作系统的定位
操作系统由两个基本功能: 1) 防止硬件被时空的应用程序滥用; 2) 向应用程序提供简单一致的机制来控制复杂而又通常大相径庭的低级硬件设备。
4.2 什么是进程/任务(Process/Task)
每个应用程序运行于现代操作系统之上时,操作系统会提供一种抽象,好像系统上只有这个程序在运行,所有的硬件资源都被这个程序在使用。这种假象是通过抽象了一个进程的概念来完成的,进程可以说是计算机科学中最重要和最成功的概念之一。
进程是操作系统对一个正在运行的程序的一种抽象,换言之,可以把进程看做程序的一次运行过程;同时,在操作系统内部,进程又是操作系统进行资源分配的基本单位。
4.3 进程控制块抽象(PCB Process Control Block)
计算机内部要管理任何现实事物,都需要将其抽象成一组有关联的、互为一体的数据。在 Java
语言中,我们可以通过类/
对象来描述这一特征。
//
以下代码是
Java
代码的伪码形式,重在说明,无法直接运行
class
PCB
{
//
进程的唯一标识
—— pid;
//
进程关联的程序信息,例如哪个程序,加载到内存中的区域等
//
分配给该资源使用的各个资源
//
进度调度信息(留待下面讲解)
}
这样,每一个 PCB 对象,就代表着一个实实在在运行着的程序,也就是进程。操作系统再通过这种数据结构,例如线性表、搜索树等将 PCB 对象组织起来,方便管理时进行增删查改的操作。
4.4 CPU 分配 —— 进程调度(Process Scheduling)
为了便于讨论和理解,我们大部分的场景下假设是单CPU
单核的计算机。操作系统对CPU
资源的分配,采用的是时间模式
——
不同的进程在不同的时间段去使用
CPU
资源。
4.5 内存分配 —— 内存管理(Memory Manage)
操作系统对内存资源的分配,采用的是空间模式 ——
不同进程使用内存中的不同区域,互相之间不会干扰。
4.6 进程间通信(Inter Process Communication)
如上所述,进程是操作系统进行资源分配的最小单位,这意味着各个进程互相之间是无法感受到对方存在的,这就是操作系统抽象出进程这一概念的初衷,这样便带来了进程之间互相具备”
隔离性
(
Isolation
)
“
。但现代的应用,要完成一个复杂的业务需求,往往无法通过一个进程独立完成,总是需要进程和进程进行配合地达到应用的目的,如此,进程之间就需要有进行“
信息交换
“
的需求。进程间通信的需求就应运而生。
目前,主流操作系统提供的进程通信机制有如下:
1. 管道 2. 共享内存 3. 文件 4. 网络 5. 信号量 6. 信号
其中,网络是一种相对特殊的 IPC
机制,它除了支持同主机两个进程间通信,还支持同一网络内部非同一主机上的进程间进行通信。