第一部分 概述
综述
本书从几个生动的计算机程序实例引入,带我们走进了一个庞大的计算机世界。计算机系统的诞生经历了无数个创新性时刻,每一个看似显然的成果都是来之不易的。比如,让计算机用一种我们能够理解的语言和我们交谈,就包含预处理、编译、链接、执行四个过程,每一个过程的进行和两个过程之间的过渡都包含极其复杂的机器语言转换。又比如,让计算机系统能够快速响应我们的指令,它需要一个高性能的处理器作为“大脑”,这个处理器的架构与制程包纳了极其复杂的电路设计,任何一个极微小的差错都会造成极其可怕的后果,而“超标量处理器”的诞生,更是经历了一代又一代的革新与改进,最终达到了极致的精巧。如果我们深入去学习,就会发现每一个要点都可以去无穷无尽地去挖掘。
计算机语言部分
计算机只认得零和壹,而我们的正常语言包含千千万万种指令,这种从复杂到简单的转化过程,光想想就是宏伟的工程。在几百年的历史中沉淀下来的编程语言精华,从底层到上层,是机器语言、汇编语言、源程序语言、图形化语言。图形化语言接近我们的生活,几乎不需要学习;原程序语言开始使我们困惑,因为它有很多限制,只有这些限制才保证了语言更严格地向下传递;汇编语言已经令我们头晕,因为它分步执行,死板不通,同时极容易出错,但只有这种严酷的死板才能被进一步简化传达;机器语言俨然是本天书,真正地将我们的语言体系与属于计算机自己的语言体系分隔。
本书重点介绍了源程序语言的特殊性质和汇编语言的寄存器实现。在学习过程中,我们要体悟到,造成源程序语言所有特殊性质的根本,是二进制语言的编码技巧。我们用零和壹去表示整数、浮点数,用二进制算法去表示加减乘除,这个过程看似简单,实则包含深刻的数学。
比如,补码的引入就不是显然的,但这并不显然的东西在时间的磨砺中留存下来,因为它在计算机语言的计算过程中提供了相当程度的便捷。补码加法、补码的非、补码乘法,等等,在正常思路中的数学二进制计算很复杂时,换个思路,在补码的范畴中想一想。
又比如,我们在十进制数学中并不习惯用移位来处理计算,但在计算机语言中,移位的思想深刻进入了计算机处理器中,因为它是单次计算的最简洁表达。从十进制算术转化到二进制算术中,移位操作数不胜数,我们如何用最少的移位达到最高的效率?这其中就有深刻的数学原理。
还比如,二进制典型的逻辑运算发展成了布尔数学,因为它尽管只是零和壹,但当千千万万个零和壹组合起来,它就需要一种规整有效的形式归纳表达。
这样的例子有很多,它们告诫我们,千万不要用一种简单的视角看待形式简单的二进制计算机语言,而是将它当作一门数学加以研究。此外,我们需要注意到在计算机语言中某些反常的地方,它们会在各处出现,造成他们的原因是C语言中的符号表示。这个要点在C语言编程时一定要铭记在心。
处理器部分
作为计算机的“大脑”,处理器的复杂程度超出想象。我们不可能在有限的课程中深入了解处理器,只是借助概念性的学习,掌握它最基本的运行思路。在下面归结为三点。
第一,计算机有它自己的脉搏——时钟。尽管计算机在处理任务时工作极其复杂,貌似毫无条理,但它的每一次操作无一例外地遵守内在时钟的“滴答声”。一次“滴答”,一次操作。现代处理器已经有2~3GHz的频率,我们人脑是不可能实现这样的运算速度的。
第二,现代处理器应用流水线化处理,实现了表观上“一次时钟,多条指令”的效果,大大提升了计算机性能。但这个过程并没有违背“一次‘滴答’,一次‘操作’”的基本原理,而是借助向量转化和良好的分块(也就是任务的提取分配),实现了“超标量处理”。
第三,处理器要对各种异常进行处理。如果不是这样,一个小小的差错就会导致处理器瘫痪。现代的处理器非常聪明,它自身还携带者数据分析提取的元件,加上其自身体系中具有的“流水线冒险”的预处理机制,这些措施共同保证它工作的稳定高效。
储存器部分
在储存器的学习中,我们不仅要分析储存器的原理,更要从储存器的硬件发展中去体会这一点。储存器从诞生到现在已经几百年了,人们一直想让它更大、更快、更廉价。但人们渐渐发觉,实现这三者的代价是完全不一样的,增加密度(从而降低成本)比降低访问时间容易得多。对比1985年和2015年,在SRAM、DRAM、旋转磁盘、CPU的数据密度和读取速度调查中,我们发现数据密度的提升相当明显,尤其是DRAM(44000倍)和旋转磁盘(3000000倍),但它们的读取速度并没有显著提高。
与此相对应的措施是进行储存器层次结构的设计。高速储存器容量小,靠近处理器;低速储存器容量大,远离处理器,并由上级更小更快的储存器调用。
正是由于这个储存器硬件发展背景,我们才有了种种应对复杂的“储存器层次结构设计”的概念名词,诸如“缓存命中”、“缓存不命中”、“冲突命中”、“冲突不命中”,等等。实践经验告诉我们,加强科学研究,提升储存器的速度固然是很重要的一部分,但与此同时,良好的储存器结构设计的作用不容小觑,它们两者共同提升了我们计算机的性能。
程序与系统优化部分
程序与系统优化的原理完全来自于之前所学的内容。如果完全不知道计算机的内部构造,就不可能彻底理解程序优化,对优化程度的分析更是无从谈起。举几个例子。在储存器部分所学的“储存器山”,告诉我们编写“对高速缓存友好”的代码,充分利用“时间局部性”和“空间局部性”,就能提升高达十倍以上性能。在处理器部分,我们了解到,采用流水线化架构的处理流程,我们能获得远多于每个时钟周期一条指令的处理效率,这在超标量处理器问世之前是不可想象的。
第二部分 心得
写在前面
在“心得”这一部分,我关注的重点将不再局限于本书涉及的知识点,而拓展至日常生活中与计算机有关的点点滴滴。接下来的部分也许比较零碎,没有课程知识体系的完整性,但包含了对计算机世界的绝对好奇。下面的两个例子并不是凭空举出的,其中很大一部分是从本书的学习过程中产生好奇,自发探索。在每一个实例中,我会尽量联系书中知识点,做到活学活用。
部分英特尔第七代处理器的部分参数
CPU型号 |
I5-7200U |
I7-7500U |
I7-7700K |
E7-8870 V4 |
核心/线程 |
2/4 |
2/4 |
4/8 |
20/40 |
频率 |
2.5~3.1 GHz |
2.7~3.5 GHz |
4.2~4.5 GHz |
2.1~3.0 GHz |
一级数据缓存 |
2×32 KB |
2×32 KB |
4×32 KB |
未知 |
一级指令缓存 |
2×32 KB |
2×32 KB |
4×32 KB |
未知 |
二级缓存 |
2×256 KB |
2×256 KB |
4×256 KB |
未知 |
三级缓存 |
3 MB |
4 MB |
8 MB |
50 MB |
制程 |
14 nm |
14 nm |
14 nm |
14 nm |
功耗 |
15 W |
15 W |
91 W |
140 W |
【注:以上数据来自于英特尔官网】
数据分析
1. 在储存器部分我们接触了“储存器山”,了解到处理器中的三级缓存的大小差距,这个事实在以上四款英特尔第七代处理器中得到验证。
2. 在处理器的发展过程当中,人们意识到增加核心数比提升处理器频率更为廉价,且更容易控制功耗。我们从数据中看到,尽管至强处理器E7-8870 V4将核心数增加到了20个,它的功耗相比酷睿旗舰处理器i7-7700K 只是提高了49W。多核处理器更有利于发挥协作机制,提供低功耗下的高效率。
3. 对比以上三款酷睿处理器,我们应该意识到高速缓存在处理器性能中的重要作用。处理器的重要参数远不仅仅是核心数的多少和频率的高低。
传统机械硬盘和固态硬盘的性能对比
硬盘型号 |
SUMSUNG 750 EVO SATAⅢ |
SUMSUNG NVMe M.2 |
SUMSUNG M8 |
读取速度 |
540 MB/s |
3500 MB/s |
140 MB/s |
写入速度 |
520 MB/s |
2100 MB/s |
145 MB/s |
平均无故障时间 |
1,500,000 h |
1,500,000 h |
未知 |
容量 |
250 GB |
2 TB |
1 TB |
价格 |
1099 RMB |
9399 RMB |
450 RMB |
【注:以上数据来自于中关村】
数据分析
1. 固态硬盘的生产厂家千千万,我只选取了著名的三星企业,是为了加强对比性。
2. 在这个表格中的前两款硬盘是固态硬盘,分别采用的是相对落后的SATA接口和新一代NVMe M.2接口。我们看到,在读写速度上,固态硬盘有着非常显著的优势。采用新一代接口的SUMSUNG NVMe M.2 的读写速度达到SUMSUNG M8的大约20倍。目前,限制固态硬盘更大范围推广的因素主要是价格,其次是寿命。高性能固态硬盘的价格高得离谱,这使得普通用户没有接近它们的机会。大部分固态硬盘的读写寿命对于普通用户绰绰有余,但达不到企业的要求。然而,固态硬盘将成为外接储存的未来,这一点是毋庸置疑的。