好奇的探索者,理性的思考者,踏实的行动者。
Table of Contents:
《计算机组成与设计:软 / 硬件接口》(第 5 版)
《深入理解计算机系统》(第 3 版)
《程序员的自我修养——链接、装载和库》
《编码:隐匿在计算机软硬件背后的语言》
《计算机体系结构:量化研究方法》
《大话计算机》
《数据密集型应用系统设计》
体系结构、操作系统、编译原理以及计算机网络,都可以认为是组成原理的后继课程。体系结构不是一个系统软件,它更多地是讲,如何量化地设计和研究体系结构和指令集。操作系统、编译原理和计算机网络都是基于体系结构之上的系统软件。
其实操作系统也是一个“软件”,而开发操作系统,只需要关注到“组成原理”或者“体系结构”就好了,不需要真的了解硬件。操作系统,其实是在“组成原理”所讲的“指令集”上做一层封装。
体系结构、操作系统、编译原理以及计算机网络,都可以认为是组成原理的后继课程。体系结构不是一个系统软件,它更多地是讲,如何量化地设计和研究体系结构和指令集。操作系统、编译原理和计算机网络都是基于体系结构之上的系统软件。
在硬件 和软件之间需要一座桥梁,而“计算机组成原理”就扮演了这样一个角色,它既隔离了软件
和硬件,也提供了让软件无需关心硬件,就能直接操作硬件的接口。
组成原理是计算机其他核心课程的一个“导引”。学习组成原理之后,向下,你
可以学习数字电路相关的课程,向上,你可以学习编译原理、操作系统这些核心课程。
CPU、内存和主板、以及I/O 设备
主板的芯片组(Chipset)和总线(Bus)解决了 CPU 和内存之间如何通信的问题。
芯片组控制了数据传输的流转,也就是数据从哪里到哪里的问题。
总线则是实际数据传输的高速公路。
因此,总线速度(Bus Speed)决定了数据能传输得多快。
冯·诺依曼体系结构(Von Neumann architecture),也叫存储程序计算机。
什么是存储程序计算机呢?
这里面其实暗含了两个概念,一个是“可编程”计算机,一个 是“存储”计算机。
比如:计算器的本质是一个不可编程的计算机可“存储”,其实是说,程序本身是存储在计算机的内存里,可以通过加
载不同的程序来解决不同的问题。
图灵机就是一个抽象的“思维实验”,而冯·诺依曼机就是对应着这个“思维实验”的“物理实现”。如果我们把“图灵机”当成“灵魂”,代表计算机最抽象的本质,那么“冯诺伊曼机”就是“肉体”,代表了计算机最具体的本质。这两者之间颇有理论物理学家和实验物理学家的合作关系的意思,可谓是一个问题的两面。
任何一台计算机的任何一个部件都可以归到运算器、控制器、存储器、输入设备和输出设备
中,而所有的现代计算机也都是基于这个基础架构来设计开发的。
而所有的计算机程序,也都可以抽象为从输入设备读取输入信息,通过运算器和控制器来执
行存储在存储器里的程序,最终把结果输出到输出设备中。
可以说,冯·诺依曼体系结构确立了我们现在每天使用的计算机硬件的基础架构。
因此,学习计算机组成原理,其实就是学习和拆解冯·诺依曼体系结构。
具体来说,学习组成原理,其实就是学习控制器、运算器的工作原理,
也就是 CPU 是怎么工作的,以及为何这样设计;
学习内存的工作原理,从最基本的电路,到上层抽象给到CPU 乃至应用程序的接口是怎样的;
学习 CPU 是怎么和输入设备、输出设备打交道的。
学习组成原理,就是在理解从控制器、运算器、存储器、输入设备以及输出设备,从电路这
样的硬件,到最终开放给软件的接口,是怎么运作的,为什么要设计成这样,以及在软件开
发层面怎么尽可能用好它。
冯·诺依曼机和[[图灵机]]的区别(Turing Machine)?
冯·诺依曼机侧重于硬件抽象,而图灵机侧重于计算抽象。
从这张图可以看出来,整个计算机组成原理,就是围绕着计算机是如何组织运作展开的
计算机组成原理的英文叫 Computer Organization。
《计算机是怎样跑起来的》
《程序是怎样跑起来的》
《计算机组成与设计:硬件 / 软件接口》
《深入理解计算机系统》
《计算机组成:结构化方法》
《计算机体系结构:量化研究方法》
《编码:隐匿在计算机软硬件背后的语言》
《程序员的自我修养:链接、装载和库》
两个指标。
第一个是响应时间(Response time)或者叫执行时间(Execution time)。想要提升响
应时间这个性能指标,你可以理解为让计算机“跑得更快”。
第二个是吞吐率(Throughput)或者带宽(Bandwidth),想要提升这个指标,你可以理
解为让计算机“搬得更多”。
提升吞吐率的办法有很多。大部分时候,我们只要多加一些机器,多堆一些硬件就好了。但
是响应时间的提升却没有那么容易,因为 CPU 的性能提升其实在 10 年前就处于“挤牙
膏”的状态了
虽然时间是一个很自然的用来衡量性能的指标,但是用时间来衡量时,有两个问题。
第一个就是时间不“准”。
计算机可能同时运行着好多个程序,CPU 实际上不停地在各个程序之间进行切换。
在这些走掉的时间里面,很可能 CPU 切换去运行别的程序了。而且,有些程序在运行的时
候,可能要从网络、硬盘去读取数据,要等网络和硬盘把数据读出来,给到内存和 CPU。
其次,即使我们已经拿到了 CPU 时间,我们也不一定可以直接“比较”出两个程序的性能
差异。
我们需要对“时间”这个我们可以感知的指标进行拆解,把程序的 CPU 执行时间变成 CPU
时钟周期数(CPU Cycles)和 时钟周期时间(Clock Cycle)的乘积。
程序的 CPU 执行时间 = CPU 时钟周期数(CPU Cycles)× 时钟周期时间(Clock Cycle)
程序的 CPU 执行时间 = 指令数 × CPI × Clock Cycle Time
每条指令的平均时钟周期数(Cycles Per Instruction,简称 CPI)
因此,如果我们想要解决性能问题,其实就是要优化这三者。
时钟周期时间,就是计算机主频,这个取决于计算机硬件。
我们所熟知的摩尔定律就一直在不停地提高我们计算机的主频。比如说,我最早使用的 80386 主频只有 33MHz,现在手头的笔记本电脑就有 2.8GHz,在主频层面,就提升了将近 100 倍。
每条指令的平均时钟周期数 CPI,就是一条指令到底需要多少 CPU Cycle。
在后面讲解CPU 结构的时候,我们会看到,现代的 CPU 通过流水线技术(Pipeline),让一条指令
需要的 CPU Cycle 尽可能地少。因此,对于 CPI 的优化,也是计算机组成和体系结构中的重要一环。
指令数,代表执行我们的程序到底需要多少条指令、用哪些指令。
这个很多时候就把挑战交给了编译器。同样的代码,编译成计算机指令时候,就有各种不同的表示方式。
总结延伸
我们可以看到,无论是简单地通过提升主频,还是增加更多的 CPU 核心数量,通过并行来提升性能,都会遇到相应的瓶颈。仅仅简单地通过“堆硬件”的方式,在今天已经不能很好地满足我们对于程序性能的期望了。于是,工程师们需要从其他方面开始下功夫了。
加速大概率事件。
最典型的就是,过去几年流行的深度学习,整个计算过程中,99% 都是向量和矩阵计算,于是,工程师们通过用 GPU 替代 CPU,大幅度提升了深度学习的模型训练过程。本来一个 CPU 需要跑几小时甚至几天的程序,GPU 只需要几分钟就好了。Google 更是不满足于 GPU 的性能,进一步地推出了 TPU。
通过流水线提高性能。
现代的工厂里的生产线叫“流水线”。我们可以把装配 iPhone 这样的任务拆分成一个个细分的任务,让每个人都只需要处理一道工序,最大化整个工厂的生产效率。类似的,我们的 CPU 其实就是一个“运算工厂”。我们把 CPU 指令执行的过程进行拆分,细化运行,也是现代 CPU 在主频没有办法提升那么多的情况下,性能仍然可以得到提升的重要原因之一。
通过预测提高性能。
通过预先猜测下一步该干什么,而不是等上一步运行的结果,提前进行运算,也是让程序跑得更快一点的办法。典型的例子就是在一个循环访问数组的时候,凭经验,你也会猜到下一步我们会访问数组的下一项。