TL;DR:计算机从底层到上层,本质是一条由简单部件层层堆叠而成的链路——电子开关组成逻辑门,逻辑门搭出能算数的 ALU 和能记忆的寄存器/RAM,控制单元 CU 用时钟驱动"取码-解码-执行"的指令周期,编程语言再把人类指令翻译成 0 和 1,最后由操作系统用进程抽象统一管理硬件资源。读完本文,你将彻底看穿计算机这台"黑箱"。

目录

一、冯·诺依曼体系:现代计算机的统一骨架

人类对"计算"的需求驱动着工具演进:一般计算工具 → 机械计算机 → 电子计算机。而今天几乎所有计算机都遵循同一套结构——冯·诺依曼体系(Von Neumann Architecture)

它由五大部件组成:

部件职责
输入设备用户给计算机发号施令(键盘、鼠标)
输出设备计算机向用户汇报结果(显示器、音箱)
存储器存储数据和指令,全部用二进制,分内存和外存
运算器做算术运算和逻辑判断
控制器指挥各部件协同工作

其中运算器 + 控制器 = CPU(中央处理器)。数据沿着"输入设备 → 存储器 ↔ CPU → 输出设备"流动。

两个必须刻进脑子的不等式:

存储空间大小:  硬盘 > 内存 >> CPU
数据访问速度:  CPU  >> 内存 > 硬盘

这正是"为什么CPU要配高速缓存""为什么程序要先加载进内存才能跑"这类问题的根源。

冯·诺依曼(John von Neumann,1903–1957),美籍匈牙利数学家、计算机科学家、物理学家,被称为"现代计算机之父"“博弈论之父”。

下面进入最硬核的部分:CPU究竟是怎么用一堆开关造出来的。

二、第一块多米诺骨牌:电子开关

一切的起点是机械继电器(Mechanical Relay)——一个电子开关:下方线圈通电产生磁场,吸合上方机械臂,电路导通;断电则弹开。

它就像一个水龙头:打开有水,关闭断水。输入 TRUE 输出 TRUE,输入 FALSE 输出 FALSE。

别小看这个"只表示 1 位(bit)"的笨器件——后来的真空管、晶体管,物理原理更复杂,本质都在做同一件事:用通电/断电表示 1 和 0

把这些开关巧妙组合,就能造出真正有用的东西——门电路(Gate Circuit)

三、逻辑门:计算机世界的"原子"

用电子开关可以搭出四种最基础的逻辑门,它们各自对应一张真值表:

  • 非门 NOT:输入取反(进1出0,进0出1)
  • 与门 AND:两个输入全为1才输出1(两个开关串联)
  • 或门 OR:只要有一个为1就输出1(两个开关并联)
  • 异或门 XOR:两个输入不同才输出1(可由 AND / OR / NOT 组合而成)
        ┌─────┐         A ─┐        ┌─────┐
   1 ───│ NOT ├──0          ├─ AND ├──      ┌─────┐
        └─────┘         B ─┘        └─────┘  A,B不同才出1 → XOR

逻辑门看起来简单,但它是数学与电路的第一次握手。接下来,见证奇迹的时刻——用它们造一个会算数的部件

四、ALU:计算机的"数学大脑"

**ALU(Arithmetic & Logic Unit,算术逻辑单元)**是计算机里做算数和逻辑运算的核心部件。著名的 Intel 74181 就是一块经典的 4 位 ALU 芯片。

要理解它,先回到进制。

4.1 二进制:一切数字的底色

十进制 183 = 1×100 + 8×10 + 3×1,每位权重是 10 的幂;
二进制同理,每位权重是 2 的幂:

183 = 1×128 + 1×32 + 1×16 + 1×4 + 1×2 + 1×1
    = 10110111 (二进制)

二进制相加和十进制竖式完全一样,只是逢二进一

  10110111  (183)
+ 00010011  ( 19)
-----------
  11001010  (202)

4.2 半加器:两个 1 位相加

两个 1 位二进制数 A、B 相加,结果有两部分:和(SUM)进位(CARRY)

  • 和 = A XOR B
  • 进位 = A AND B

一个 XOR + 一个 AND,就组成了半加器(Half Adder)

AB进位
0000
0101
1001
1110

4.3 全加器与 8 位加法器

半加器只能处理两个输入,但竖式加法中第二位开始还要加上来自低位的进位,于是有三个输入。用两个半加器 + 一个或门组成全加器(Full Adder)

再把 1 个半加器和 7 个全加器像链条一样串联(低位进位喂给高位),就得到一个完整的 8 位加法器

至此,一个能算 8 位数加法的运算器,就被我们从无到有"焊"了出来。继续组合逻辑门,减法、乘法、除法都能实现(乘除法器更复杂)。这就是 ALU 中算术单元的来历。

4.4 逻辑单元

ALU 的另一半是逻辑单元,负责与、或、非以及大小比较等。比如把 8 位数字逐位接进一串 OR 门,只要有一位是 1 输出就是 1——这就是一个"8 位非 0 判断器"(判断结果是否为 0,再取反即可)。

最终的 ALU 对外长这样:吃进两个 8 位输入 A、B,接收一个 4 位操作码 opcode告诉它做什么运算,输出 8 位结果,同时给出溢出、是否为 0、正负数等标志位

再复杂的现代 64 位 ALU,也是工程师这样一层一层抽象出来的。

五、寄存器与内存:让计算机"记住"东西

光会算没用,得有地方存数据。存储同样能用门电路造出来,而且关键特性是:必须保持通电,一旦断电数据就丢失(易失 volatile)——这就是内存断电即失的硬件原因。

5.1 锁存器:1 位的记忆

用 AND、OR、NOT 门交叉反馈,可以搭出 AND-OR 锁存器(Latch),它能"咬住"一个状态不放。再封装成带数据输入(Data)使能线(Write Enable)门锁(Gated Latch)

  • 使能线置位:输入什么就存什么(进1存1,进0存0);
  • 使能线关闭:写入无效,保持原值。

5.2 从寄存器到 RAM

  • 把 8 个门锁并排,共用一根使能线,就是一个 8 位寄存器(Register)
  • 把海量这样的存储单元排成矩阵,配上地址线、数据线、读/写使能线,就构成了 RAM(Random Access Memory,随机存取存储器)

RAM 可以通过地址直接定位到任意一格,访问时间与位置无关——这正是 O(1) 时间复杂度,也是为什么编程语言里"数组用下标访问是 O(1)"的硬件支撑。

六、控制单元 CU 与指令周期:计算机是如何"自己动起来"的

有了 ALU(会算)和存储(会记),还差一个"发号施令"的角色——控制单元 CU(Control Unit)。它负责指挥 ALU 去算什么、何时去内存取数。

CU 内部有两个关键寄存器:

  • PC(Program Counter,程序计数器):保存下一条要执行的指令在内存中的地址
  • IR(Instruction Register,指令寄存器):保存当前这条指令本身

6.1 指令:CPU 唯一能听懂的话

指令(Instruction)= 操作码(opcode)+ 被操作数

  • 操作码说明"做什么动作";
  • 被操作数说明"对谁操作",可能是内存地址,也可能是寄存器编号。

指令本身也是一个数字,以二进制形式躺在内存里。一张简化指令表:

指令功能opcode操作数
LOAD_A从 RAM 指定地址取数到寄存器 A00104 位地址
LOAD_B取数到寄存器 B00014 位地址
STORE_A把 A 的数据写回 RAM 指定地址01004 位地址
ADD两个寄存器相加,结果放回第二个1000两个寄存器 ID

6.2 完整跑一条指令

以内存第 0 格存着 0010 1110 为例:

  1. 取码(Fetch):CU 按 PC 的值(0),从内存地址 0 把指令 00101110 读入 IR;
  2. 解码(Decode):查表得知前 4 位 0010 是 LOAD_A,后 4 位 1110 = 十进制 14,即"把内存地址 14 的数据读到寄存器 A";
  3. 执行(Execute):CU 指挥完成动作,把地址 14 的数据搬进寄存器 A;
  4. PC 自增 +1,指向下一条指令,循环往复。

这就是永不停歇的指令周期(Instruction Cycle)

        取码 Fetch
            │
            ▼
      解码 Decode  ──────► 执行 Execute ──┐
            ▲                            │
            └────────────────────────────┘

这个周期不是 CPU 自己"想"出来的节奏,而是由一颗**时钟(Clock)**周期性驱动的。CPU 主频粗略地讲就是时钟每秒震荡的次数,可以近似看作每秒能执行的指令节拍数——这就是你在"我的电脑属性"里看到的 1.60GHz / 2.11GHz。

至此:ALU + CU + 寄存器 + 时钟 = CPU。CPU 通过地址总线告诉内存要哪个地址、通过数据总线取回或写入数据。

贴士:

  1. PC 寄存器决定了 CPU 下一条执行哪条指令
  2. 指令由动作 + 操作对象组成;
  3. CPU 眼中只有指令,没有"文件""图片"这些概念

七、编程语言:从拨 0/1 开关到高级语言

程序(Program)= 一组指令 + 这组指令要处理的数据。 狭义上,它通常表现为磁盘上的一组文件。

最早的微型电脑 Altair 8800,编程真的要靠面板上的开关,一位一位地把 0、1 拨进去——门槛极高。为了把人从二进制里解放出来,编程语言经历了三层演进:

高级语言(C / Java …)
   │  编译 compile + 链接 link
   ▼
汇编语言(LOAD_A、ADD 这类助记符,与机器指令一一对应)
   │  汇编 assemble(汇编器 assembler)
   ▼
机器语言(0 和 1,CPU 唯一直接执行的东西)
  • 汇编语言:用人类好记的符号一一对应机器指令,但程序员仍需掌握全部硬件细节,且换一类机器就不通用;
  • 高级语言(C、Java 等):屏蔽硬件细节,经编译器(compiler)、链接器(linker)、汇编器层层翻译成机器语言。

注意:高级语言里的**一条语句(Statement),往往对应很多条机器指令(Instruction)**才能完成。

封装让编程越来越容易,但也让很多程序员把计算机当成"黑箱"。理解这一层,你就明白自己写的代码最终是如何变成 0 和 1 去驱动硬件的。

八、操作系统:站在硬件与程序之间的管理者

**操作系统(OS)**是一组做计算机资源管理的软件的统称(Windows、Linux、macOS、Android、iOS、鸿蒙等)。

系统的分层视图:

┌─────────────────────────────┐
│          应用程序            │
├─────────────────────────────┤
│          操作系统            │
├──────────┬────────┬─────────┤
│  处理器   │  主存   │ I/O设备 │
└──────────┴────────┴─────────┘

它有两个基本功能:

  1. 防止硬件被失控的应用程序滥用
  2. 向应用程序提供简单一致的接口,去控制那些复杂且差异巨大的底层硬件。

8.1 进程:最重要的抽象之一

每个程序运行时,OS 都会制造一种"这台机器上只有我在独占运行"的假象。这个抽象就是进程(Process / Task)

  • 进程是对一个正在运行的程序的抽象,可以理解为"程序的一次运行过程";
  • 在 OS 内部,进程又是资源分配的基本单位

OS 用一个数据结构描述每个进程——PCB(Process Control Block,进程控制块),里面记录进程标识 pid、关联的程序与内存区域、占用的资源、调度信息等。可以类比成 Java 里的一个对象:

// 伪码,仅用于说明概念
class PCB {
    long pid;                       // 进程唯一标识
    // 关联的程序信息、加载到内存的区域
    // 分配到的各类资源
    // 调度信息
}

OS 再用线性表、搜索树等结构把这些 PCB 组织起来,方便增删查改。

8.2 进程调度与内存管理

  • CPU 分配 —— 进程调度(时间模式):在单 CPU 上,多个进程在不同时间段轮流使用 CPU,制造并行的错觉;
  • 内存分配 —— 内存管理(空间模式):不同进程使用内存中的不同区域,彼此隔离、互不干扰。

8.3 进程间通信 IPC

隔离保证了安全,但复杂业务又需要进程协作,于是有了进程间通信(IPC)。主流机制包括:

  1. 管道 2. 共享内存 3. 文件 4. 网络 5. 信号量 6. 信号

其中网络最特殊:它不仅支持同一台主机上的两个进程通信,还能跨越不同主机。

结语

电子开关 → 逻辑门 → 加法器/ALU → 锁存器/寄存器/RAM → CU 驱动指令周期(取码-解码-执行)→ 汇编/高级语言翻译成指令 → 操作系统用进程抽象统一管理资源。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐