⚙️ 第九章 操作系统与应用程序的关系
📄 一句话概括

同一个【把字送到屏幕上】的动作,可以在高级语言、系统调用、硬件三个高度上写——越高越省事,越低越看得清。

📝 本节和前面几节的关系

9.3 说的是系统调用这一层,这一节把三层摆在一起看。

一、三层,同一个动作

高级语言:print("hi")——你只管表达意思。 系统调用:os.write(1, b"hi")——你把字节交给谁。 硬件:把字符写进显存——谁真的去点亮像素。 实测三种写法的结果完全一样,区别只在你站在哪一层上说话。

二、每一层替你做掉了什么

语言运行时替你做:把对象变成字节、管缓冲、处理编码错误。 操作系统替你做:找到设备、排队、调度、保证别人也能用。 硬件替你做:把电信号变成像素。 每往上一层,你要操心的东西就少一圈——这正是抽象化的定义。

三、代价:看不见底下

抽象的好处是不用管底下,代价是看不见底下。 出问题的时候最明显:屏幕上就是没字,你既不知道是缓冲没刷、还是权限不够、还是驱动挂了。 所以【懂得往下看】是一种实打实的能力:在高层查不出来时,往下一层走一层。 这也是这一章、乃至这本书一直在做的事:把底下那几层翻出来看一遍。

四、抽象化带来的另一个好处

不只是【省事】,还有【可替换】。 上面那层不用知道下面是什么。 屏幕从 CRT 换成液晶、从 24 寸换成 4K,print 那一行代码一个字都不用改。 同一套接口,底下的东西可以整个换掉——这就是抽象化最值钱的地方。 第六章讲的 SSD 替换机械硬盘、第七章讲的虚拟机替换 CPU,用的都是这同一条原理。

五、动手 Demo:操作系统和高级编程语言对硬件进行了抽象化

同一个动作——把几个字送到屏幕上——可以站在三个不同的高度上写。 从高到低各写一遍,看结果是不是同一个。

import io, os
buf = io.StringIO()
print("hi", end="", file=buf)   # 高级写法
buf.write("hi")                # 稍低一层
r, w = os.pipe()
os.write(w, b"hi")             # 最低层:直接写字节
os.close(w)
print(os.read(r, 2))
os.close(r)

实跑输出:

--------------------------------------------------------------------
操作系统和高级编程语言对硬件进行了抽象化
--------------------------------------------------------------------

同一个动作——**把几个字送到屏幕上**——可以站在三个不同的高度上写。

  层次         写法                   谁在处理
  -----------------------------------------------
  高级语言     print("hi")            语言运行时
  系统调用     os.write(1, b"hi")     操作系统
  硬件         把字符写进显存         驱动与硬件

  从高到低各写一遍,结果都是同样的两个字符:

    print("hi")
    sys.stdout.write("hi")
    os.write(1, b"hi")

    实测:print 写进缓冲的      'hi'
    实测:write 写进缓冲的      'hi'
    实测:os.write 送进管道的    'hi'

  **三者结果完全一样,只是站的层次不同。**
  区别只在【你在哪一层把自己的意思说出来】:
    高级语言  让【意思】清楚——你写的是【打印这句话】
    系统调用  让【动作】规范——你把字节交给谁
    硬件层    让【电信号】落地——谁真的去点亮像素

  **抽象化的代价是【看不见底下】,好处是【不用管底下】。**
  这本书一直在做的事,就是**把底下那一层翻出来看。**

实测三种写法拿到的结果完全一致(都是 b'hi' 或 'hi')。 区别只在【你在哪一层把自己的意思说出来】——越高越省事,越低越看得清。

30 秒实验

  1. 把 print 换成 os.write 写一次输出,看看少了哪些方便。
  2. 想一想:为什么换了显示器,你的程序一个字都不用改。

常见误区

  1. 以为抽象化只是【省事】。它更值钱的地方是【底下可以整个换掉】。
  2. 以为越低层越好。低层看得清但费力,多数时候高层才是对的。
自测三问(点开对答案) 1. 三层抽象分别是什么? —— 高级语言、系统调用、硬件——越高越省事,越低越接近真实动作。 2. 抽象化的两个好处是什么? —— 不用管底下(省事),以及底下可以整个替换而不影响上层。 3. 抽象化的代价是什么? —— 看不见底下,出了问题不容易判断到底卡在哪一层。

相关笔记