2026/2/12 11:21:42
网站建设
项目流程
医院网站云服务器配置,库尔勒网站建设哪家专业,wordpress怎么安装模板文件,佛山市seo推广前言
这两天在读《深入理解计算机系统》#xff08;CSAPP#xff09;这本书#xff0c;它从程序员的视角系统地讲解了计算机系统的底层原理#xff0c;是计算机科学领域公认的一本神书#xff0c;也是卡内基梅隆大学#xff08;CMU#xff09;的镇校之作。
读完了第一…前言这两天在读《深入理解计算机系统》CSAPP这本书它从程序员的视角系统地讲解了计算机系统的底层原理是计算机科学领域公认的一本神书也是卡内基梅隆大学CMU的镇校之作。读完了第一章确实感到其名不虚传。第一章计算机系统漫游从章节标题来看好像是对计算机系统的简单介绍但它带给我的感觉绝不仅仅是简单的介绍夸张一点来讲它甚至构建了整个计算机系统的世界观。读完这一章最大的收获在于加深了我对计算机底层的三个核心的理解信息的本质、系统的抽象、存储的层次。本篇文章作为我的一篇读书笔记将会以上面的三个核心为主以编译系统和 Amdahl 定律为辅尝试着整理出计算机系统的基础脉络。1. 信息的本质这是全书开篇提出的第一个颠覆性的概念也是理解计算机底层表示的基础“信息 位 上下文”。在计算机中无论是我们写的代码存储的数据还是网络传输的包本质上都只是位即 0 和 1 组成的序列。我们在平时写代码时其实对数据类型是非常敏感的但在计算机底层所有信息本质上都是无意义的 0 和 1 序列真正赋予它们意义的是解读这串序列时的上下文。同样的字节序列在文本上下文中可能表示字符a但在整数上下文中就表示数值97。理解了这一点我们其实可以回想一下 C 语言中的强制类型转换这个概念为什么会出现乱码其实本质上就是我们在用错误的上下文去解读一串位序列。1.1 什么是上下文正如我们上面所讲计算机硬件只认识位序列它并不会知道这串位序列表示的是浮点数还是整数。而区分不同数据对象的唯一方法就是我们读到这个数据对象时的上下文。上下文一般都包括数据类型这是特定的编程语言或者编译器指定的。存储位置这串数据是放在栈堆还是代码段里面。字节序应该以大端还是小端的方式来解读这串数据。执行环境程序是在 x86-64 架构下还是 ARM 架构下运行的。没有了上下文位序列就毫无意义。我们试想一个简单的场景你现在要阅读别人的一份代码你通常习惯于使用英文来理解变量名的含义而他的代码中变量名恰好是使用拼音来命名的好在我们作为人类是具有思考能力的琢磨一会也许就反应过来了。但是对于计算机他并没有思考能力当你不明确指定一串序列的上下文时它就完全无法知道这串序列是什么意思。当你指定了一个错误的上下文时他也会按照这个上下文去解读这串序列但这样做得到的结果自然不是我们期待的。计算机并没有分辨是非的能力它需要引导这就是上下文存在的意义。1.2 示例这里举个简单的例子请看下面代码#includestdio.hintmain(){inti97;char*c(char*)i;printf(i的地址%p\n,i);printf(指针c%p\n,c);printf(作为整数: %d\n,i);printf(作为字符: %c\n,*c);return0;}代码中定义了一个int类型的局部变量i并初始化为97然后我们将变量i的地址强制转换成char *类型并传给指针c。接着我们使用两个printf打印出i的地址和指针变量c的值后面程序运行时我们可以看到打印出的这两个值其实是相同的这里的强制类型转换只是让计算机以char来解读该地址存放的值。然后再用两个printf分别以整数和字符的格式将这个地址的值打印出来。运行结果如下可以看到打印出来的确实是同一个地址。对这个地址中的值以不同的上下文进行解读我们得到的是完全不同的结果这里没有乱码是因为97刚好是字符a的ASCII码。我们将i的值改为250再试试可以看到打印出乱码了。2. 系统的抽象第一章最精彩的部分在于解释了操作系统到底在做什么简单来说操作系统通过抽象在硬件和软件之间搭建了沟通的桥梁。如果程序员直接操作硬件难免会出现粗心大意的情况不仅复杂而且危险。为了保护硬件和方便编程操作系统提供了三个最基本的抽象给程序制造了幻觉。2.1 文件 — 对 I/O 设备的抽象所有的 I/O 设备比如磁盘、键盘、显示器、网络都被视为一串字节流。不同的设备有完全不同的物理特性。但是我们不需要了解具体的硬件技术细节只需要通过 I/O 接口read和write读写文件即可。在 Linux 中一切皆文件这一设计极大地简化了输入输出操作。2.2 虚拟内存 — 对主存和磁盘的抽象每个程序都以为自己独占了主存拥有一个巨大的连续的地址空间。但是实际上物理内存可能很小且被多个程序共享。虚拟内存是操作系统最复杂的抽象之一它为每个进程提供了一个一致的虚拟地址空间结构。从下往上依次是程序代码和数据从可执行文件中加载。堆程序运行时动态申请内存。共享库比如 C 标准库。栈函数调用链。内核虚拟内存操作系统驻留的地方。这种抽象不仅简化了链接和加载还保护了各进程的地址空间互不干扰。2.3 进程 — 对CPU、主存和I/O的总和抽象每个进程都以为自己独占了 CPU。但是实际上操作系统通过上下文切换机制让 CPU 在多个进程间快速切换因为切换速度极快看起来就像是多个程序在同时运行。现代系统中一个进程内部还可以有多个线程。线程是运行在进程上下文中的执行单元它们共享代码和全局数据相比进程更加轻量级。3. 存储的层次这部分是连接理论与实践的桥梁。3.1 核心矛盾摩尔定律揭示了 CPU 的发展速度极其迅猛但内存 DRAM 的访问速度提升却相对缓慢。如果 CPU 每执行一条指令纳秒级都要等待主存读取数据百纳秒级别CPU 将大部分时间处于空转等待状态如此系统的性能将被内存拖垮。3.2 解决方案为了解决这个核心矛盾计算机系统设计了一个类似金字塔的层次结构。核心思想是利用造价便宜、容量大的存储设备作为速度快、造价高、容量小的存储设备的“缓存”。下面这个金字塔模型是从书里面截取下来的3.3 局部性原理为什么加了缓存就变快了呢这是因为程序运行具有局部性时间局部性刚访问过的数据很可能马上再次被访问。空间局部性访问了某个地址的数据很可能马上访问它旁边的数据。理解了这一层级结构之后我们在写代码时就应该注重对缓存友好这往往比降低算法的时间复杂度带来的性能提升更加直接。比如在 C 语言中按行遍历二维数组通常比按列遍历快得多就是因为按行遍历缓存命中率更高利用了空间局部性。4. 其他重要的概念第一章中还有两个概念值得一提它们贯穿了后续章节。4.1 编译系统的四个阶段下面这个流程图是从书中截取的预处理插入头文件替换宏。编译翻译成汇编语言。汇编翻译成二进制机器代码。链接合并库函数。4.2 Amdahl 定律这是一个关于系统性能提升的定律它和木桶效应具有一定的相似之处。当我们对系统的一个部分的性能进行提升时对系统整体性能的影响取决于该部分被使用的频率。就拿这张图来说吧如果我们不断增加完好的木板的长度桶里面能装的水的量并不能提升因为我们增加的那部分根本不会被使用到但是如果我们增加断开的木板的长度那么储水量将会大大提升。虽然 Amdahl 定律主要讲的是加速比但用木桶效应来理解瓶颈决定系统上限也是非常直观的。第一章的漫游就到此为止我们下一篇文章再见。