编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • 计算机原理

    • README
    • 计算机组成结构原理
      • 01.工作案例引入
        • 1.1 一次线上事故
        • 1.2 为什么要学硬件
      • 02.计算机底层知识
        • 2.1 计算机基础组成
        • 2.2 应该怎么学
        • 2.3 计算机发展历程
      • 03.计算机基本硬件
        • 3.1 基本硬件组成
        • 3.2 输入输出设备
        • 3.3 硬件协作流程
      • 04.冯诺依曼体系结构
        • 4.1 存储程序计算机
        • 4.2 冯诺依曼计算机
        • 4.3 抽象计算机框架
        • 4.4 冯诺依曼体系
        • 4.5 理解案例概念
        • 4.6 数据交互层设计
        • 4.7 数据流动层设计
        • 4.8 控制层面设计
        • 4.9 一道练习题
      • 05.计算机组成原理
        • 5.1 计算机知识地图
        • 5.2 计算机基本组成
        • 5.3 控制器
        • 5.4 存储器
        • 5.5 输入设备
        • 5.6 输出设备
        • 5.7 运算器
        • 5.8 五大部件协作
      • 06.深入冯诺依曼架构
        • 6.1 为什么存储程序
        • 6.2 哈佛vs冯诺依曼
        • 6.3 现代混合架构
        • 6.4 冯诺依曼瓶颈
        • 6.5 突破瓶颈思路
      • 07.计算机性能功耗
        • 7.1 如何衡量性能
        • 7.2 性能公式推导
        • 7.3 功耗墙问题
        • 7.4 阿姆达尔定律
      • 08.如何学习原理
        • 8.1 知识体系太大
        • 8.2 如何学该专栏
      • 09.综合案例按键显示
        • 9.1 场景背景
        • 9.2 完整流程分解
        • 9.3 五大部件角色
        • 9.4 性能公式复盘
      • 10.思考题与作业
        • 10.1 基础思考题
        • 10.2 进阶思考题
        • 10.3 动手作业
    • 计算器存储器的原理
    • 计算机基础CPU设计
    • 系统CPU缓存的设计
    • 计算机输入输出设备
    • 计算机总线系统设计
    • 计算机指令编程原理
    • 计算机程序如何执行
    • 计算机内存设计原理
    • 计算机二进制和字节
    • 计算机异常处理机制
    • 计算机IO操作和原理
  • 网络协议

  • 操作系统

  • 数据库原理

  • 计算机
  • 计算机原理
杨充
2023-03-07
目录

计算机组成结构原理

# 01.计算机组成结构原理

# 目录介绍

  • 01.工作案例引入
    • 1.1 一次线上事故
    • 1.2 为什么要学硬件
  • 02.计算机底层知识
    • 2.1 计算机基础组成
    • 2.2 应该怎么学
    • 2.3 计算机发展历程
  • 03.计算机基本硬件
    • 3.1 基本硬件组成
    • 3.2 输入输出设备
    • 3.3 硬件协作流程
  • 04.冯诺依曼体系结构
    • 4.1 存储程序计算机
    • 4.2 冯诺依曼计算机
    • 4.3 抽象计算机框架
    • 4.4 冯诺依曼体系
    • 4.5 理解案例概念
    • 4.6 数据交互层设计
    • 4.7 数据流动层设计
    • 4.8 控制层面设计
    • 4.9 一道练习题
  • 05.计算机组成原理
    • 5.1 计算机知识地图
    • 5.2 计算机基本组成
    • 5.3 控制器
    • 5.4 存储器
    • 5.5 输入设备
    • 5.6 输出设备
    • 5.7 运算器
    • 5.8 五大部件协作
  • 06.深入冯诺依曼架构
    • 6.1 为什么存储程序
    • 6.2 哈佛vs冯诺依曼
    • 6.3 现代混合架构
    • 6.4 冯诺依曼瓶颈
    • 6.5 突破瓶颈思路
  • 07.计算机性能功耗
    • 7.1 如何衡量性能
    • 7.2 性能公式推导
    • 7.3 功耗墙问题
    • 7.4 阿姆达尔定律
  • 08.如何学习原理
    • 8.1 知识体系太大
    • 8.2 如何学该专栏
  • 09.综合案例按键显示
    • 9.1 场景背景
    • 9.2 完整流程分解
    • 9.3 五大部件角色
    • 9.4 性能公式复盘
  • 10.思考题与作业
    • 10.1 基础思考题
    • 10.2 进阶思考题
    • 10.3 动手作业

# 01.工作案例引入

# 1.1 一次线上事故

场景:小李是一名工作三年的后端工程师。有天凌晨三点被电话吵醒——线上某个"核心接口"的响应时间从平均 20ms 飙升到 2s,监控告警此起彼伏。值班同事已经把能重启的服务都重启了一遍,无效。

小李登上生产机,top 一看:

%Cpu(s):  5.2 us,  3.1 sy,  0.0 ni, 20.5 id, 71.0 wa,  0.0 hi,  0.2 si
                                             ^^^^^^^^
                                         等待 I/O 的时间占了 71%
1
2
3

疑惑:CPU 其实很闲(id+wa=91%),那为什么接口这么慢?为什么 wa(I/O wait)这么高,到底在等什么?为什么重启服务不管用?

继续追查发现:同机房的一块 SSD 出现预警,磁盘随机读延迟从 100μs 涨到了 80ms,而这个接口每次请求都要读几十次小文件。

追问链:

  • "为什么 CPU 很闲,接口却很慢?" → 因为 CPU 在等磁盘,CPU 和外设速度差 10 万倍
  • "为什么 CPU 不能直接读硬盘,要通过内存?" → 因为冯·诺依曼架构规定 CPU 只和内存打交道
  • "那为什么内存断电数据就丢了?" → 因为内存是 DRAM,存储机制决定了它的易失性
  • "为什么不全用 SSD 当内存?" → 因为速度差百倍、寿命有限——这就是存储层次的设计权衡
  • "为什么告警出现后,业务先卡的是这一个接口?" → 因为这个接口的指令执行路径上堆了大量 I/O 指令,其他接口走了别的路径

这一连串追问,答案都写在"计算机组成原理"这本书里。

# 1.2 为什么要学硬件

小李这次事故的根本问题不是代码写错了,而是对硬件没有感觉。他写的是 Java,平时关心的是 Spring、MyBatis、线程池,但系统真正的性能曲线是由下面这些硬件特性决定的:

flowchart LR
    A[业务代码] -->|你以为| B[服务返回]
    A -->|实际上| C[指令]
    C --> D[CPU]
    D -->|99% 时间| E[内存/缓存]
    E -->|1000x 延迟| F[磁盘/网络]
    style E fill:#ffe4b5
    style F fill:#ffb6c1
1
2
3
4
5
6
7
8

本章的目标,就是把"计算机"这台机器拆开给你看,让你建立起最基本的硬件直觉:

  • 它由哪些部件组成?
  • 这些部件的速度差异有多大?
  • 为什么要这样设计,能不能改?
  • 程序员写的每一行代码,在这个硬件模型里会走哪条路径?

带着这五个问题,我们开始。

# 02.计算机底层知识

# 2.1 计算机基础组成

计算机是由 CPU、内存、显示器这些设备组成的硬件。目前,大部分程序员都是从事各种软件开发工作。显然,在硬件和软件之间需要一座桥梁,而"计算机组成原理"就扮演了这样一个角色,它既隔离了软件和硬件,也提供了让软件无需关心硬件,就能直接操作硬件的接口。

只需要对硬件有原理性的理解,就可以信赖硬件的可靠性,用高级语言来写程序。无论是写操作系统和编译器这样的硬核代码,还是写 Web 应用和手机 App 这样的应用层代码,都可以做到心里有底。

无论你想要学习计算机的哪一门核心课程,之前都应该先学习一下"计算机组成原理",这样无论是对计算机的硬件原理,还是软件架构,对计算机方方面面的知识都会有一个全局的了解。

疑惑:为什么软件开发者也需要了解硬件?

很多程序员觉得自己只写上层代码,不需要关心底层硬件。但实际上,你写的每一行代码最终都要在硬件上运行。比如:

  • 为什么同样的算法,在不同的数据结构上性能差距巨大?——因为内存访问模式影响了 CPU 缓存命中率
  • 为什么并发程序会出现诡异的 Bug?——因为 CPU 多核缓存一致性、指令重排序
  • 为什么某些 I/O 操作特别慢?——因为磁盘寻道、DMA 传输机制

理解了这些,你才能写出真正高性能的代码。

# 2.2 应该怎么学

说了这么多计算机组成原理的重要性,但到底该怎么学呢?"买书如山倒,读书如抽丝"。从业这么多年,周围想要好好学一学组成原理的工程师不少,但是真的坚持下来学完、学好的却不多。

对这些问题,从学习和工作的经验看,找到了三个主要原因。

  • 第一,广。组成原理中的概念非常多,每个概念的信息量也非常大。比如想要理解 CPU 中的算术逻辑单元(也就是 ALU)是怎么实现加法的,需要牵涉到如何把整数表示成二进制,还需要了解这些表示背后的电路、逻辑门、CPU 时钟、触发器等知识。
  • 第二,深。组成原理中的很多概念,阐述开来就是计算机学科的另外一门核心课程。比如,计算机的指令是怎么从你写的 C、Java 这样的高级语言,变成计算机可以执行的机器码的?如果我们展开并深入讲解这个问题,就会变成《编译原理》这样一门核心课程。
  • 第三,学不能致用。学东西是要拿来用的,但因为这门课本身的属性,很多人在学习时,常常沉溺于概念和理论中,无法和自己日常的开发工作联系起来,以此来解决工作中遇到的问题,所以,学习往往没有成就感,就很难有动力坚持下去。

# 2.3 计算机发展历程

疑惑:计算机是怎么从笨重的机器一步步演变到今天轻薄的笔记本和手机的?

计算机的发展经历了五个主要阶段,每一代的核心变化都在于计算元器件的演进:

代际 时间 核心元件 特点 代表
第一代 1946-1958 电子管 体积巨大、耗电量大、易损坏 ENIAC
第二代 1958-1964 晶体管 体积缩小、可靠性提高 IBM 7090
第三代 1964-1971 集成电路(IC) 小型化、成本降低 IBM 360
第四代 1971-至今 大规模/超大规模集成电路 微处理器诞生 Intel 4004 → 现代CPU
第五代 探索中 量子计算/光计算/生物计算 突破经典计算极限 量子计算机

关键里程碑:

  • 1946年 ENIAC:第一台通用电子计算机,重达30吨,占地170平方米
  • 1947年 晶体管发明:贝尔实验室,奠定了现代电子学的基础
  • 1958年 集成电路:Jack Kilby 发明,可以在一块芯片上集成多个晶体管
  • 1971年 Intel 4004:第一款微处理器,2300个晶体管
  • 2024年 Apple M4:约280亿个晶体管

论证——摩尔定律:Intel 创始人之一戈登·摩尔在1965年预言:集成电路上可容纳的晶体管数量,约每隔18-24个月翻一番。这条定律驱动了半个多世纪的芯片产业发展,但如今已经接近物理极限(原子尺度约0.1nm),行业正在探索3D堆叠、新材料等方式继续提升。

# 03.计算机基本硬件

# 3.1 基本硬件组成

早年,要自己组装一台计算机,要先有三大件,CPU、内存和主板。

CPU,它是计算机最重要的核心配件,全名你肯定知道,叫中央处理器(Central Processing Unit)。为什么说 CPU 是"最重要"的呢?因为计算机的所有"计算"都是由 CPU 来进行的。自然,CPU 也是整台计算机中造价最昂贵的部分之一。

内存(Memory),你撰写的程序、打开的浏览器、运行的游戏,都要加载到内存里才能运行。程序读取的数据、计算得到的结果,也都要放在内存里。内存越大,能加载的东西自然也就越多。

主板,存放在内存里的程序和数据,需要被 CPU 读取,CPU 计算完之后,还要把数据写回到内存。然而 CPU 不能直接插到内存上,反之亦然。于是,就带来了最后一个大件——主板(Motherboard)。

主板的核心作用:主板是所有硬件的"交通枢纽"。它上面有各种总线(Bus)、芯片组(Chipset)、各种接口插槽。总线就像城市的道路,数据通过总线在 CPU、内存、硬盘、显卡之间流转。芯片组则像交通调度中心,控制着数据的路由方向。

flowchart TB
    subgraph MB[主板 Motherboard]
        CPU[CPU 插槽]
        MEM[内存插槽 DDR]
        CHIP[芯片组 Chipset]
        PCIE[PCIe 插槽 显卡/SSD]
        SATA[SATA 接口 HDD]
        USB[USB/网口]
    end
    CPU <-->|前端总线| CHIP
    MEM <-->|内存总线| CPU
    CHIP <--> PCIE
    CHIP <--> SATA
    CHIP <--> USB
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3.2 输入输出设备

有了三大件,只要配上电源供电,计算机差不多就可以跑起来了。但是现在还缺少各类输入(Input)/ 输出(Output)设备,也就是我们常说的 I/O 设备。

如果你用的是自己的个人电脑,那显示器肯定必不可少,只有有了显示器我们才能看到计算机输出的各种图像、文字,这也就是所谓的输出设备。

同样的,鼠标和键盘也都是必不可少的配件。这样我才能输入文本,写下这篇文章。它们也就是所谓的输入设备。

# 3.3 硬件协作流程

疑惑:这些硬件是怎么协同工作的?它们之间是什么关系?

我们通过一个"打开浏览器访问网页"的完整过程来理解:

1. 你双击浏览器图标(输入设备:鼠标)
       ↓
2. 操作系统收到点击事件,从硬盘读取浏览器程序(存储器:硬盘)
       ↓
3. 程序被加载到内存中(存储器:内存)
       ↓
4. CPU 从内存读取指令,开始执行浏览器启动逻辑(处理器:CPU)
       ↓
5. 浏览器界面渲染到显示器上(输出设备:显示器)
       ↓
6. 你在地址栏输入网址(输入设备:键盘)
       ↓
7. CPU 处理后,通过网卡发出网络请求(I/O设备:网卡)
       ↓
8. 网卡接收到网页数据,写入内存(I/O设备 → 内存)
       ↓
9. CPU 解析 HTML/CSS/JS,计算页面布局(处理器:CPU)
       ↓
10. 渲染结果输出到显示器(输出设备:显示器)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

结论:所有硬件各司其职,通过总线互联互通,由 CPU 统一调度协调。这就是冯·诺依曼体系结构的实际体现。

# 04.冯诺依曼体系结构

# 4.1 存储程序计算机

无论是个人电脑、服务器、智能手机,还是 Raspberry Pi 这样的微型卡片机,都遵循着同一个"计算机"的抽象概念。

这是怎么样一个"计算机"呢?这其实就是,计算机祖师爷之一冯·诺依曼(John von Neumann)提出的冯·诺依曼体系结构(Von Neumann architecture),也叫存储程序计算机。

什么是存储程序计算机呢?这里面其实暗含了两个概念,一个是"可编程"计算机,一个是"存储"计算机。

1.说到"可编程",估计你会有点懵,你可以先想想,什么是"不可编程"。

计算机是由各种门电路组合而成的,然后通过组装出一个固定的电路板,来完成一个特定的计算程序。一旦需要修改功能,就要重新组装电路。这样的话,计算机就是"不可编程"的,因为程序在计算机硬件层面是"写死"的。

最常见的就是老式计算器,电路板设好了加减乘除,做不了任何计算逻辑固定之外的事情。

2.再来看"存储"计算机。这其实是说,程序本身是存储在计算机的内存里,可以通过加载不同的程序来解决不同的问题。

有"存储程序计算机",自然也有不能存储程序的计算机。

典型的就是早年的"Plugboard"这样的插线板式的计算机。整个计算机就是一个巨大的插线板,通过在板子上不同的插头或者接口的位置插入线路,来实现不同的功能。

这样的计算机自然是"可编程"的,但是编写好的程序不能存储下来供下一次加载使用,不得不每次要用到和当前不同的"程序"的时候,重新插板子,重新"编程"。

疑惑:为什么"存储程序"这个概念如此重要?

答疑:在存储程序出现之前,"程序"和"数据"是分离的。程序硬编码在电路中(或者通过插线板配置),数据从外部输入。这意味着每换一个计算任务,就要重新接线。

论证:ENIAC 就是这样的机器,每次更换计算任务需要数天时间重新接线。而冯·诺依曼提出的关键洞见是:程序本身也是数据。既然数据可以存储在内存中,程序也可以!这样,切换计算任务就变成了"加载不同的程序到内存",几秒钟就能完成。

结论:这个看似简单的想法,奠定了现代计算机的基石。你的手机能同时运行微信、浏览器、音乐播放器,本质上就是因为这些程序都以数据的形式存储在内存中,CPU 按需执行。

# 4.2 冯诺依曼计算机

冯祖师爷,描述了他心目中的一台计算机应该长什么样。

  • 首先是一个包含算术逻辑单元(Arithmetic Logic Unit,ALU)和处理器寄存器(Processor Register)的处理器单元(Processing Unit),用来完成各种算术和逻辑运算。因为它能够完成各种数据的处理或者计算工作,因此也有人把这个叫作数据通路(Datapath)或者运算器。
  • 然后是一个包含指令寄存器(Instruction Register)和程序计数器(Program Counter)的控制器单元(Control Unit/CU),用来控制程序的流程,通常就是不同条件下的分支和跳转。在现在的计算机里,上面的算术逻辑单元和这里的控制器单元,共同组成了我们说的 CPU。
  • 接着是用来存储数据(Data)和指令(Instruction)的内存。以及更大容量的外部存储,在过去,可能是磁带、磁鼓这样的设备,现在通常就是硬盘。
  • 最后就是各种输入和输出设备,以及对应的输入和输出机制。我们现在无论是使用什么样的计算机,其实都是和输入输出设备在打交道。个人电脑的鼠标键盘是输入设备,显示器是输出设备。我们用的智能手机,触摸屏既是输入设备,又是输出设备。而跑在各种云上的服务器,则是通过网络来进行输入和输出。这个时候,网卡既是输入设备又是输出设备。
flowchart LR
    IN[输入设备<br/>键盘/鼠标/网卡] --> MEM[(存储器<br/>内存+硬盘)]
    MEM <--> CPU
    subgraph CPU[CPU]
        CU[控制器 CU<br/>IR/PC]
        ALU[运算器 ALU<br/>寄存器]
        CU <--> ALU
    end
    MEM --> OUT[输出设备<br/>显示器/打印机]
    CU -.控制信号.-> IN
    CU -.控制信号.-> OUT
1
2
3
4
5
6
7
8
9
10
11

# 4.3 抽象计算机框架

任何一台计算机的任何一个部件都可以归到运算器、控制器、存储器、输入设备和输出设备中,而所有的现代计算机也都是基于这个基础架构来设计开发的。

而所有的计算机程序,也都可以抽象为从输入设备读取输入信息,通过运算器和控制器来执行存储在存储器里的程序,最终把结果输出到输出设备中。

我们所有撰写的无论高级还是低级语言的程序,也都是基于这样一个抽象框架来进行运作的。

冯·诺依曼结构也称作普林斯顿结构,是一种将程序和数据存放在同一存储器不同地址的设计概念,其核心特点如下:

  • 计算机由运算器、控制器、存储器、输入和输出设备五个部分组成
  • 数据和程序均以二进制代码形式不加区分地存放在存储器中,具体位置由存储器地址决定
  • 顺序执行程序,即计算机工作时,先把要执行的程序和处理的数据存入存储器 (内存),然后自动并按顺序从存储器中取出指令逐一执行

用一张表格总结冯·诺依曼架构的核心设计原则:

原则 含义 现代体现
二进制表示 所有数据和指令都用二进制编码 0和1对应电路高低电平
存储程序 程序和数据统一存储在内存中 RAM中加载的进程
顺序执行 默认按地址顺序逐条执行指令 程序计数器PC自动+1
五大部件 运算器+控制器+存储器+输入+输出 CPU+内存+硬盘+键鼠+显示器

# 4.4 冯诺依曼体系

冯·诺依曼体系结构确立了我们现在每天使用的计算机硬件的基础架构。因此,学习计算机组成原理,其实就是学习和拆解冯·诺依曼体系结构。

具体来说,学习组成原理,其实就是学习控制器、运算器的工作原理,也就是 CPU 是怎么工作的,以及为何这样设计;学习内存的工作原理,从最基本的电路,到上层抽象给到 CPU 乃至应用程序的接口是怎样的;学习 CPU 是怎么和输入设备、输出设备打交道的。

学习组成原理,就是在理解从控制器、运算器、存储器、输入设备以及输出设备,从电路这样的硬件,到最终开放给软件的接口,是怎么运作的,为什么要设计成这样,以及在软件开发层面怎么尽可能用好它。

# 4.5 理解案例概念

假设在一个假期中,小杨突然想起了一个许久没有联系的朋友,随机在电脑中打开了QQ,在对话框中输入了要发送的消息,随即向朋友发送了过去。

通过该综合案例理解冯诺依曼体系结构

  1. 小杨打开QQ软件,这个时候程序运行前,需要把它加载到内存中。这是由体系结构决定的,cpu只能从内存中读取数据,不会直接和外设拿"数据"。
  2. 写的代码要编译成二进制指令,是要交由cpu进行处理,因为cpu要根据接收到的指令来完成工作,当接收到二进制的指令后,分析好要处理的数据,根据和自己的指令集"比对"确定要怎样"处理"!
  3. 小杨通过键盘输入消息,这个过程称之为IO过程(input/output)。会将消息通过二进制在内存中传输,这个就涉及到内存和外设交互的过程。
  4. 消息通过网络向朋友发去,朋友那边收到消息,二进制数据需要序列化,会首先加载数据到内存内存中。这个解决数据的过程是在CPU中进行的,CPU不和外设"打交道",只和内存打交道。
  5. 最后,将消息打印到显示器中。这个是输出过程,输出通过IO流程,最终通过界面形式展现出来。

# 4.6 数据交互层设计

冯诺依曼体系结构,在数据交互层面是如何设计的。CPU不会和外设直接打交道,只会和内存交互。所有的外设如果有数据需要载入只能载入到内存,内存写出的数据也一定是写到外设中去。

疑惑:为什么 CPU 不直接和硬盘、键盘等外设交互,非要通过内存中转?

答疑:这其实是一个"木桶原理"的问题。

设备 速度量级 比喻
CPU 寄存器 ~0.3ns 闪电
内存(DRAM) ~100ns 快递小哥
SSD 硬盘 ~100μs 骑自行车
机械硬盘 ~10ms 走路
网络请求 ~100ms 坐火车
flowchart LR
    R[寄存器<br/>0.3ns] --> L1[L1 Cache<br/>1ns]
    L1 --> L2[L2/L3<br/>10ns]
    L2 --> M[内存 DRAM<br/>100ns]
    M --> S[SSD<br/>100μs]
    S --> H[HDD<br/>10ms]
    H --> N[网络<br/>100ms]
    style R fill:#90EE90
    style M fill:#FFD700
    style N fill:#FF6B6B
1
2
3
4
5
6
7
8
9
10

如果 CPU 直接读硬盘,就像让"闪电"等"走路的人"——CPU 99% 的时间都在空等。通过内存做中间层,操作系统可以提前把数据从硬盘搬到内存(预取),CPU 需要时直接从内存拿,速度差从 10 万倍缩小到 100 倍。

论证:这也是为什么"程序运行前要先加载到内存"的根本原因。不是内存想抢硬盘的活,而是 CPU 太快了,硬盘太慢了,内存是两者之间最合适的"中间人"。

# 4.7 数据流动层设计

举例现在你在和你的网友进行QQ聊天,你发了一条消息到网友接受到消息中间经历了那些硬件?

完整的数据流动是什么样的,首先你将消息通过键盘输入,载入到内存中属于QQ的那块空间,然后通过CPU对消息进行处理(加密之类的)然后再写回内存中,内存将数据写到网卡中。

通过网络发送到网友电脑的网卡,然后将接受到的数据写入内存,CPU处理后再写回内存,从内存再写到显示器上。

完整流程示意:

你的电脑:
  键盘(输入) → 内存(QQ进程空间) → CPU(加密处理) → 内存 → 网卡(输出)
      ↓ 网络传输
朋友的电脑:
  网卡(输入) → 内存(QQ进程空间) → CPU(解密处理) → 内存 → 显示器(输出)
1
2
3
4
5

注意每一步数据都要经过内存,CPU 永远只和内存打交道,这就是冯·诺依曼体系的精髓。

# 4.8 控制层面设计

当我们通过键盘将数据输入,内存是如何知道外设中有数据需要加载到内存中呢?当内存中的数据要往磁盘的写的话是什么时候写的(肯定不是随时写的,太慢了)也就是缓冲区是什么时候清空的呢。

这里的控制信号由CPU的控制器负责发出。控制器又是在执行谁的指令来控制这些外设和内存呢?实际是操作系统(Operator System),操作系统是在幕后一直帮助CPU进行决策的。

深入理解控制流程:

操作系统(决策层)
    ↓ 发出控制指令
CPU 控制器(执行层)
    ↓ 通过控制总线发出控制信号
各个设备(硬件层)
    ├── 内存:收到读/写信号,执行操作
    ├── 硬盘:收到DMA传输指令,搬运数据
    ├── 键盘:产生中断信号,通知CPU有输入
    └── 显示器:收到显存数据,刷新画面
1
2
3
4
5
6
7
8
9

这里涉及两个重要机制:

  • 中断机制:外设不会一直占用CPU,而是有数据时发中断通知CPU
  • DMA机制:大块数据传输(如硬盘到内存)不需要CPU逐字节搬运,由DMA控制器代劳

# 4.9 一道练习题

例题:冯诺依曼机的基本工作方式是:A.控制流驱动方式;B.多指令多数据流方式;C.微程序控制方式;D.数据流驱动方式

答案:A;冯·诺依曼机工作方式,可称为控制流(指令流)驱动方式。即按照指令的执行序列,依次读取指令,然后根据指令所含的控制信息,调用数据进行处理。

B属于多处理机,冯诺依曼机是单指令流和单数据流系统;数据流驱动方式指:只有当一条或一组指令所需的操作数全部准备好时,才能激发相应指令的一次执行,执行结果又流向等待这一数据的下一条或一组指令,以驱动该条或该组指令的执行。

因此,程序中各条指令的执行顺序仅仅是由指令间的数据依赖关系决定的。

存储程序的概念是指将指令以代码形式事先输入计算机的主存储器,然后按其在存储器中的首地址执行程序的第一条指令,以后就按程序的规定顺序执行其他指令,直至程序执行结束。

# 05.计算机组成原理

# 5.1 计算机知识地图

从这张图可以看出来,整个计算机组成原理,就是围绕着计算机是如何组织运作展开的。

知识地图可以划分为四大模块:

flowchart TB
    ROOT[计算机组成原理]
    ROOT --> A[1.指令与编译]
    ROOT --> B[2.处理器设计]
    ROOT --> C[3.存储器系统]
    ROOT --> D[4.I/O 系统]
    A --> A1[高级语言→汇编→机器码]
    A --> A2[编译器/汇编器/链接器]
    A --> A3[指令集架构 ISA]
    B --> B1[控制器<br/>取指/解码/执行]
    B --> B2[运算器 ALU/FPU]
    B --> B3[流水线/超标量/乱序]
    C --> C1[寄存器→Cache→内存→硬盘]
    C --> C2[虚拟内存/地址映射]
    C --> C3[缓存一致性]
    D --> D1[总线架构]
    D --> D2[中断与 DMA]
    D --> D3[输入输出接口]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 5.2 计算机基本组成

计算机是由哪些硬件组成的。这些硬件,又是怎么对应到经典的冯·诺依曼体系结构中的,也就是运算器、控制器、存储器、输入设备和输出设备这五大基本组件。

除此之外,你还需要了解计算机的两个核心指标,性能和功耗。性能和功耗也是我们在应用和设计五大基本组件中需要重点考虑的因素。

在计算机指令部分,需要搞明白,我们每天撰写的一行行 C、Java、PHP 程序,是怎么在计算机里面跑起来的。

这里面,你既需要了解我们的程序是怎么通过编译器和汇编器,变成一条条机器指令这样的编译过程(如果把编译过程展开的话,可以变成一门完整的编译原理课程),还需要知道我们的操作系统是怎么链接、装载、执行这些程序的(这部分知识如果再深入学习,又可以变成一门操作系统课程)。

而这一条条指令执行的控制过程,就是由计算机五大组件之一的控制器来控制的。

在计算机的计算部分,要从二进制和编码开始,理解我们的数据在计算机里的表示,以及我们是怎么从数字电路层面,实现加法、乘法这些基本的运算功能的。

实现这些运算功能的 ALU(Arithmetic Logic Unit/ALU),也就是算术逻辑单元,其实就是我们计算机五大组件之一的运算器。

# 5.3 控制器

控制器是计算机的指挥中心,由其指挥各部件自动协调地进行工作。控制器由程序计数器PC、指令寄存器IR和控制单元CU组成。

PC用于存放当前欲执行指令的地址,可自动+1以形成下一条指令的地址,与主存的MAR之间有一条直接通路。

IR用来存放当前的指令,其内容来自主存的MDR。指令中的操作码OP(IR)送至CU,用以分析指令并发出各种微操作命令序列;地址码Ad(IR)送往MAR,用以取操作数。(操作码表示机器所执行的各种操作,地址码表示参加运算的数在存储器内的位置)

控制器的工作流程(指令周期):

flowchart LR
    F[取指 Fetch<br/>PC→MAR→MDR→IR] --> D[解码 Decode<br/>CU 分析 OP]
    D --> E[执行 Execute<br/>ALU 运算/访存]
    E --> W[写回 Write Back<br/>结果入寄存器/内存]
    W --> P[PC+1 或跳转]
    P --> F
1
2
3
4
5
6

这个循环就叫做指令周期(Instruction Cycle),CPU 从开机到关机,就在不停地执行这个循环。

# 5.4 存储器

存储器是计算机的存储部件,用来存放程序和数据。

存储器分为主存储器(主存,内存储器,内存)和辅助存储器(辅存,外存储器,外存)。CPU能够直接访问的存储器是主存。辅存用于帮助主存记忆更多信息,辅存中的信息必须调入主存后,才能被CPU访问。

主存包括存储体M、各种逻辑部件及控制电路等。

  • 存储体由许多存储单元组成,每个存储单元包含若干存储元件(或称存储基元、存储元),每个存储元件存储一位二进制代码 0 or 1。
  • 因此存储单元可存储一串二进制代码,称这串代码为存储字,称这串代码的位数为存储字长,存储字长可以是1B或是字节的偶数倍。一个存储字既可代表数,也可代表一串字符,也可代表指令等。
  • 主存的工作方式为:按存储单元的地址进行存取,这种存取方式称为按地址存取方式,即按地址访问存储器(简称按地址寻访,访存)。

存储体存放二进制信息

  • 地址寄存器(MAR)存放访存地址,经过地址译码后找到所选的存储单元。
  • 数据寄存器(MDR)用于暂存要从存储器中读或写的信息,时序控制逻辑用于产生存储器操作所需的各种时序信号。

# 5.5 输入设备

输入设备的主要功能是将程序和数据以机器所能识别和接受的信息形式输入计算机。

常见的输入设备有键盘、鼠标、扫描仪、摄像机等

# 5.6 输出设备

输出设备的任务是将计算机处理的结果以人们所能接受的形式或其他系统所要求的信息形式输出

常用的输出设备有显示器、打印机等。计算机的I/O设备是计算机与外界联系的桥梁。

# 5.7 运算器

运算器是计算机的执行部件,用于进行算术运算和逻辑运算。

算术运算是按算术运算规则进行的运算,如加、减、乘、除;逻辑运算包括与、或、非、异或、比较、移位等运算。

运算器的核心是算术逻辑单元ALU(Arithmetic and Logical Unit)运算器包含若干通用寄存器,用于暂存操作数和中间结果,如累加器ACC,乘商寄存器MQ,操作数寄存器X,变址寄存器IX,基址寄存器BR等,其中ACC,MQ,X是必须有的。

运算器内还有程序状态寄存器PSW,也称标志寄存器,用于存放ALU运算得到的一些标志信息或处理机的状态信息。

深入理解ALU——用一个加法来说明:

当执行 3 + 5 时,在 ALU 内部发生了什么?

1. 操作数 3 (二进制 0011) 加载到寄存器 A
2. 操作数 5 (二进制 0101) 加载到寄存器 B
3. 控制信号指定操作类型为"加法"
4. ALU 内部的全加器电路逐位计算:
   
   第0位: 1 + 1 = 0 (进位1)
   第1位: 1 + 0 + 1(进位) = 0 (进位1)
   第2位: 0 + 1 + 1(进位) = 0 (进位1)
   第3位: 0 + 0 + 1(进位) = 1

5. 结果 1000 (二进制) = 8 (十进制) 写入目标寄存器
6. PSW 更新标志位(无溢出、结果非零、结果为正...)
1
2
3
4
5
6
7
8
9
10
11
12

这就是计算机最底层的"计算"——纯粹的电路逻辑运算。

# 5.8 五大部件协作

疑惑:五大部件是如何协同执行一条指令的?

以执行 a = b + c(假设 b=3, c=5)为例,完整的硬件级别流程:

sequenceDiagram
    participant PC as PC
    participant MEM as 内存
    participant IR as IR
    participant CU as CU
    participant ALU as ALU/ACC
    PC->>MEM: ① PC→MAR 取指令
    MEM->>IR: 指令→IR
    IR->>CU: ② 解码操作码
    CU->>MEM: ③ 取操作数 b
    MEM->>ALU: b=3 → ACC
    CU->>MEM: ③ 取操作数 c
    MEM->>ALU: c=5 → X
    ALU->>ALU: ④ ACC+X = 8
    ALU->>MEM: ⑤ 写回 a=8
    CU->>PC: ⑥ PC+1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 06.深入冯诺依曼架构

# 6.1 为什么存储程序

疑惑:存储程序的概念看起来理所当然,为什么它被认为是计算机科学最伟大的发明之一?

答疑:在存储程序之前,"计算机"和"计算器"并没有本质区别——它们都只能执行预设好的固定功能。存储程序的革命性在于:

  1. 程序即数据:程序以二进制形式存储在内存中,与数据没有本质区别
  2. 自我修改:程序可以修改自身(虽然现代编程不推荐这样做)
  3. 通用性:同一台硬件通过加载不同程序,可以完成截然不同的任务
类比理解:
  没有存储程序 = 只会炒一道菜的厨师(换菜需要换厨师)
  有了存储程序 = 有菜谱的厨师(换菜只需要换菜谱)
  "菜谱"就是程序,"菜谱架"就是内存
1
2
3
4

# 6.2 哈佛vs冯诺依曼

疑惑:计算机架构只有冯·诺依曼一种吗?

答疑:不是。与之对应的还有哈佛架构(Harvard Architecture)。

特性 冯·诺依曼架构 哈佛架构
存储方式 指令和数据共用一个存储器 指令和数据分开存储
总线 共用一条总线 指令总线和数据总线分离
优点 设计简单、灵活性高 可以同时取指令和读数据,效率更高
缺点 取指令和读数据不能同时进行 硬件复杂度更高、成本更高
典型应用 通用计算机(PC、服务器) 嵌入式系统、DSP、单片机

哈佛架构的核心优势在于:指令和数据可以并行访问。因为它们在物理上走的是不同的"通道"。

# 6.3 现代混合架构

结论:现代CPU其实是混合架构。

在CPU外部(内存侧),使用的是冯·诺依曼架构:指令和数据混合存放在同一个内存中。

但在CPU内部(缓存侧),使用的是哈佛架构:L1 Cache 分为指令缓存(I-Cache)和数据缓存(D-Cache),分别存储指令和数据,可以并行访问。

flowchart TB
    subgraph CPU[CPU 内部 - 哈佛架构]
        IC[I-Cache 指令缓存]
        DC[D-Cache 数据缓存]
        L2[L2 Cache 统一]
        IC --> L2
        DC --> L2
    end
    L2 --> MEM[(内存 RAM<br/>冯·诺依曼架构<br/>指令+数据混合)]
1
2
3
4
5
6
7
8
9

# 6.4 冯诺依曼瓶颈

疑惑:冯·诺依曼架构有什么根本性的缺陷?

冯·诺依曼架构有一个著名的瓶颈——冯·诺依曼瓶颈(Von Neumann Bottleneck):

CPU 和内存之间的数据传输通道(总线)带宽有限。无论 CPU 多快,它处理数据的速度最终受限于从内存获取数据的速度。

CPU 处理速度:  ~10 GHz(每秒100亿次操作)
内存带宽:      ~50 GB/s
实际瓶颈:      CPU 大量时间在"等数据"
1
2
3

这就像一个天才厨师配了一个慢吞吞的传菜员——厨师炒菜极快,但食材送来太慢,厨师只能干等着。

# 6.5 突破瓶颈思路

工程师们用了多种方法来缓解这个瓶颈:

方法 原理 效果
CPU缓存(L1/L2/L3) 在CPU内部存储常用数据 减少90%+的内存访问
预取(Prefetch) 提前将可能需要的数据加载到缓存 隐藏内存延迟
多通道内存 增加并行的内存通道 增加带宽
乱序执行 CPU在等数据时先执行其他指令 提高CPU利用率
DMA I/O数据传输不经过CPU CPU专注计算
近内存计算(PIM) 把计算单元放到内存芯片上 从根本上减少数据搬运

# 07.计算机性能功耗

# 7.1 如何衡量性能

疑惑:我们经常说某台电脑"性能好",但性能到底是什么,怎么量化?

性能可以从两个维度来看:

响应时间(Latency):完成一个任务需要多长时间。比如编译一个项目需要30秒。

吞吐量(Throughput):单位时间内能完成多少任务。比如一个Web服务器每秒能处理1000个请求。

对于 CPU 来说,最基本的性能指标是:

CPU 执行时间 = 指令数 × CPI × 时钟周期

其中:
  指令数:程序包含多少条指令(由编译器决定)
  CPI (Cycles Per Instruction):每条指令平均需要几个时钟周期(由CPU微架构决定)
  时钟周期 = 1 / 主频(由芯片制程和设计决定)
1
2
3
4
5
6

# 7.2 性能公式推导

为什么理解这个公式很重要? 因为它告诉我们优化性能有三个方向:

优化方向 方法 谁负责
减少指令数 更好的算法、编译器优化 程序员 + 编译器
降低CPI 流水线、超标量、分支预测 CPU 架构师
缩短时钟周期 提高主频、更先进的制程 芯片工程师

举个实际例子:

场景:排序100万个整数

方案A(冒泡排序):
  指令数: ~10^12    CPI: 2    主频: 3GHz
  时间 = 10^12 × 2 / (3×10^9) ≈ 667 秒

方案B(快速排序):
  指令数: ~2×10^7   CPI: 3    主频: 3GHz
  时间 = 2×10^7 × 3 / (3×10^9) ≈ 0.02 秒

虽然快排的 CPI 更高(因为有递归、分支),
但指令数减少了5万倍,总体快了3万多倍。
1
2
3
4
5
6
7
8
9
10
11
12

结论:减少指令数(选对算法)往往比硬件优化更有效。

# 7.3 功耗墙问题

疑惑:为什么CPU的主频在2005年前后就停止大幅增长了?

答疑:这就是著名的"功耗墙(Power Wall)"问题。

CPU的功耗公式:

动态功耗 ∝ 电容负载 × 电压² × 频率
1

主频翻倍,功耗至少翻倍(实际上因为电压也要提高,功耗可能增长4-8倍)。当功耗增大,散热就成问题:

2000年: Pentium 4 — 主频 1.5GHz, 功耗 ~55W
2004年: Pentium 4 — 主频 3.8GHz, 功耗 ~115W
2024年: i9-14900K — 主频 6.0GHz(睿频), 功耗 ~253W
1
2
3

论证:如果按照2000年的增长趋势继续提高主频到 10GHz,CPU功耗将超过 500W——这几乎等于一个电暖器!所以行业转向了多核、异构计算等方向。

# 7.4 阿姆达尔定律

疑惑:既然单核遇到瓶颈,那堆核心数就能线性提升性能吗?

答疑:不能。这就是阿姆达尔定律(Amdahl's Law)告诉我们的:

加速比 = 1 / ((1-P) + P/N)

其中:
  P = 程序中可并行化的比例
  N = 处理器核心数
1
2
3
4
5

假设一个程序 90% 的代码可以并行化(P=0.9):

核心数N 理论加速比 提升效果
1 1.0x 基准
2 1.82x 82% ↑
4 3.08x 208% ↑
8 4.71x 371% ↑
64 8.77x 接近极限
∞ 10.0x 理论极限

结论:即使有无限多的核心,由于 10% 的串行部分的存在,加速比最多只能达到 10 倍。这就是为什么 CPU 不会无限增加核心数的原因。优化那 10% 的串行代码,比增加 100 个核心更有效。

# 08.如何学习原理

# 8.1 知识体系太大

相较于整个计算机科学中的其他科目,计算机组成原理更像是整个计算机学科里的"纲要"。这门课里任何一个知识点深入挖下去,都可以变成计算机科学里的一门核心课程。

比如说,程序怎样从高级代码变成指令在计算机里面运行,对应着"编译原理"和"操作系统"这两门课程;计算实现背后则是"数字电路";如果要深入 CPU 和存储器系统的优化,必然要深入了解"计算机体系结构"。

知识关联图谱:

flowchart TB
    ROOT[计算机组成原理<br/>本课程]
    ROOT --> A[编译原理<br/>指令生成]
    ROOT --> B[操作系统<br/>程序管理]
    ROOT --> C[数字电路<br/>硬件实现]
    A --> ARCH[计算机体系结构<br/>高级 CPU 设计]
    B --> ARCH
    C --> ARCH
    ARCH --> X[并行计算]
    ARCH --> Y[嵌入式系统]
    ARCH --> Z[计算机网络]
1
2
3
4
5
6
7
8
9
10
11

# 8.2 如何学该专栏

首先,学会提问自己来串联知识点。学完一个知识点之后,可以从下面两个方面,问一下自己。

  • 我写的程序,是怎样从输入的代码,变成运行的程序,并得到最终结果的?
  • 整个过程中,计算器层面到底经历了哪些步骤,有哪些地方是可以优化的?

以教带学的方式内化知识,无论是程序的编译、链接、装载和执行,以及计算时需要用到的逻辑电路、ALU,乃至 CPU 自发为你做的流水线、指令级并行和分支预测,还有对应访问到的硬盘、内存,以及加载到高速缓存中的数据,这些都对应着我们学习中的一个个知识点。

建议自己脑子里过一遍,最好是口头表述一遍或者写下来,这样对彻底掌握这些知识点都会非常有帮助。

写一些示例程序来验证知识点,计算机科学是一门实践的学科。计算机组成中的大量原理和设计,都对应着"性能"这个词。因此,通过把对应的知识点,变成一个个性能对比的示例代码程序记录下来,是把这些知识点融汇贯通的好方法。

推荐的学习路径:

第一阶段:建立全景(本章)
  → 理解冯·诺依曼架构五大部件
  → 理解指令执行的基本流程

第二阶段:深入二进制与编码(第10章)
  → 二进制、补码、浮点数
  → 理解数据在计算机中的表示

第三阶段:理解指令系统(第7章)
  → 指令格式、寻址方式
  → 从高级语言到机器码

第四阶段:处理器设计(第3章)
  → CPU 内部结构
  → 流水线、缓存一致性

第五阶段:存储系统(第2、4、9章)
  → 存储层次结构
  → 缓存设计、虚拟内存

第六阶段:I/O系统(第5、6、12章)
  → 总线、中断、DMA
  → I/O模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 09.综合案例按键显示

现在用一个完整案例把全章五大部件、性能公式、冯·诺依曼瓶颈全部串起来。

# 9.1 场景背景

你在文本编辑器里按下键盘上的 A 键,屏幕上随即出现一个 A 字符。这个看似瞬时的动作,其实让计算机的五大部件全部参与,并且走完了一整条指令流、数据流、控制流。

我们把这 50 毫秒左右的过程慢放给你看。

# 9.2 完整流程分解

sequenceDiagram
    participant KB as 键盘(输入)
    participant USB as USB 控制器
    participant CPU as CPU
    participant MEM as 内存
    participant GPU as 显存
    participant DSP as 显示器(输出)
    Note over KB: T=0ms ① 扫描码 0x1E
    KB->>USB: 按键事件
    USB->>CPU: ② T=0.1ms IRQ 中断
    Note over CPU: 保存 PC/PSW,查中断向量
    CPU->>MEM: ③ T=0.3ms 写入键盘缓冲区
    Note over CPU,MEM: ④ T=1ms 唤醒编辑器进程<br/>ALU 算字符位图
    CPU->>GPU: ⑤ T=5ms PCIe+DMA 传位图
    GPU->>DSP: ⑥ T=16.7ms HDMI 扫描
    Note over DSP: 像素点亮,看到 A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 9.3 五大部件角色

部件 具体承担者 这次按键中的动作 对应的冯·诺依曼术语
输入设备 键盘 把机械动作转成扫描码 I/O Input
控制器 CPU 控制单元 CU + 中断控制器 接收中断、查向量表、调度进程 Control Unit
运算器 CPU ALU 字符编码转换、字体坐标计算 Arithmetic Logic Unit
存储器 内存 + 显存 保存扫描码、进程状态、像素位图 Memory
输出设备 显示器 把显存里的像素点亮成图像 I/O Output

关键观察:

  1. CPU 从始至终只和"内存"打交道——扫描码、进程数据、像素位图都是先落到内存,再通过总线转给下一个部件。这正是冯·诺依曼架构的核心规定。
  2. 整个过程中 CPU 真正算"正事"的时间不到 1ms,剩下的时间都是总线传输和等待外设——这就是冯·诺依曼瓶颈的直观体现。
  3. 如果没有中断机制,CPU 必须轮询键盘控制器,假设以 1kHz 轮询,则键盘响应延迟至少 1ms 且 CPU 100% 空转;有了中断,CPU 平时可以跑别的程序。
  4. 如果没有 DMA,位图数据(几 KB)需要 CPU 逐字节往显存搬,会把 CPU 锁死几毫秒;DMA 让 CPU 只下达"搬运指令"后就可以去干别的。

# 9.4 性能公式复盘

回忆 7.2 节的性能公式:CPU执行时间 = 指令数 × CPI × 时钟周期。把这次按键的耗时拆开:

端到端延迟 ≈ 键盘→USB(0.1ms)
           + 中断响应(0.2ms)
           + CPU 处理字符(0.7ms)  ← 这里才是 CPU 真正干活
           + PCIe 传显存(4ms)
           + 显示器刷新等待(≤16.7ms)
           + 液晶像素响应(5~16ms)
           ≈ 30~50ms
1
2
3
4
5
6
7

结论三连:

  • 瓶颈不在 CPU:CPU 只花了 0.7ms,占整体 <2%。盲目提升 CPU 主频对这条路径毫无帮助。
  • 瓶颈在传输和等待:总线、显示器刷新率、液晶响应才是决定"按键到看到字"延迟的关键。这就是为什么电竞显示器主打 240Hz 刷新率和 1ms 响应。
  • 对程序员的启示:当你优化自己代码的用户体验时,也要学会把"端到端时间"拆成这几类组件,不要只盯着 CPU 算得快不快。

# 10.思考题与作业

# 10.1 基础思考题

  1. 五大部件对号入座:请把下列硬件分别归入冯·诺依曼五大部件(运算器/控制器/存储器/输入/输出):

    • 机械硬盘 / SSD / RAM / CPU 的 ALU / CPU 的程序计数器 PC / 键盘 / 打印机 / 触摸屏 / 网卡 / GPU
  2. 为什么程序必须先加载到内存才能运行? 请从"CPU 只和内存打交道"这个约束出发回答,并说明如果允许 CPU 直接读硬盘会有什么问题。

  3. 指令周期四个阶段(取指/解码/执行/写回)分别由哪些部件参与?请画出一次 a = b + c 指令在五大部件之间的数据流动图。

  4. 冯·诺依曼架构和哈佛架构的本质区别是什么? 为什么现代 CPU 在 L1 缓存层用哈佛架构,在内存层用冯·诺依曼架构?

# 10.2 进阶思考题

  1. Amdahl 定律的现实应用:假设你的程序 80% 可并行,现在从 4 核机器换到 32 核机器,理论上能提速多少?如果你能把可并行部分的比例从 80% 优化到 95%,效果和"堆核心"相比如何?

  2. 功耗墙与多核的因果关系:为什么 2005 年前后主频停止大幅提升,行业转向了多核?请从功耗公式 P ∝ V² × f 解释,并说明"小核 + 大核"(ARM big.LITTLE)这种异构设计是怎么进一步优化功耗的。

  3. 冯·诺依曼瓶颈的现代对策:列出至少 3 种现代 CPU/系统为缓解"CPU 比内存快 100 倍"这个差距所做的设计,并说明各自的权衡。

  4. 给老板的解释:如果你是 1.1 节故事里的小李,老板第二天问你"下次怎么避免这种事故",请用"计算机组成原理"的视角给出一个结构化回答,而不是简单说"换 SSD"。

# 10.3 动手作业

作业一(必做):在自己电脑上实测存储层次速度差。

  • 用 C 或 Java 写一个程序:分别测量"访问 L1 内数组"、"访问超过 L3 的数组"、"随机读一个 1GB 文件"的每次操作平均耗时。
  • 把测量结果填入一张表,和本章 4.6 节给的理论值对比。
  • 思考:你实测到的速度差和理论值一致吗?如果不一致,可能是哪些因素(编译器优化、Page Cache、预取)造成的?

作业二(选做):读一段汇编。

  • 写一个最简单的 C 程序 int main(){ int a=3, b=5; return a+b; },用 gcc -S -O0 生成汇编。
  • 对照本章 5.8 节"五大部件协作"流程,指出汇编里哪几行对应取指、取操作数、ALU 运算、写回。
  • 再用 -O2 编译一次,看看编译器是怎么把这段代码"优化没"的——对比冯·诺依曼架构"按顺序执行每条指令"的朴素模型,你会对"真实 CPU 的行为"有全新认识。

作业三(拓展):给一个你熟悉的业务画"冯·诺依曼数据流图"。

  • 选一个你最熟悉的接口或功能(比如"发一条微信消息"、"一次数据库查询"、"视频播放 1 秒")。
  • 仿照 9.2 节,把它从"用户动作"到"最终结果"的全过程,拆解到"哪个部件做了什么"。
  • 标出每一步的时延量级(ns / μs / ms),找出瓶颈在哪一段。这是建立硬件直觉最有效的练习。
上次更新: 2026/06/07, 18:47:40
README
计算器存储器的原理

← README 计算器存储器的原理→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式