Eileen'blog

第三章:操作系统的诞生:从裸机到管家

2026-05-10T09:04:00 文章

第三章 操作系统的诞生:从裸机到管家

你打开电脑,点开浏览器、微信、音乐播放器,三个程序同时跑着,来回切换,从没出过乱子。

你想过没有:是谁在背后管理这一切?

谁决定你的微信能用多少内存?谁保证浏览器不会把音乐播放器的数据给覆盖了?谁在感知你敲击键盘、移动鼠标?

答案是:操作系统

但在计算机诞生的头十几年,这东西根本不存在。那时的工程师想跑一个程序,得先插线、拨开关、手动加载。机器跑完一个任务,停下来,等你去换下一个。

这就像买了一辆法拉利,但每次换挡都得你下车去推轮子。

这太蠢了。

于是,1950年代中期,一批程序员开始琢磨:能不能写一个“管家程序”,常驻在机器里,自动帮人类安排任务、分配资源?

这个念头,开启了操作系统的历史。

但在讲故事之前,先记住一个关键前提。

硬件前提

操作系统的诞生依赖一个硬件跃迁:晶体管(第二代计算机)。

第一代电子管计算机(如ENIAC)动不动就烧管,运行几分钟就得检修。在这种机器上写“常驻软件”毫无意义——你还没等它启动,管子先炸了。

晶体管让计算机的可靠性大幅提升,可以连续运行数小时甚至几天不出故障。只有到了这时,让一个“管家程序”永远跑在后台,才成为可能。

记住这个前提。后面讲的每一步,都踩在晶体管铺好的路上。


一、为什么人工操作慢到让计算机大部分时间闲置?——批处理系统的诞生

先穿越回1950年代初。

你是一个“程序员”——不,那时还没有这个称呼。你更像一个电工兼操作员。

你想让计算机算一个东西。步骤是这样的:

  1. 把程序写在纸上。
  2. 把纸上的程序手工转换成机器码,打在打孔卡上。一张卡一行代码,一个程序少则几十张,多则上千张。
  3. 抱着一摞打孔卡走到机房门口,交给穿着白大褂的操作员
  4. 操作员把你的卡放进读卡机,按下启动按钮。
  5. 机器跑起来。你要等。等多久?不知道。可能半小时,可能明天。因为前面还有别人的程序在排队。
  6. 跑完了,操作员拿着一摞打印纸出来,上面是计算结果。如果算错了——你把一个分号写成了逗号——回到第1步。

注意第5步的“排队”。那不是你想象中“排着队一个一个来”的平静画面。实际情况是:一个程序跑10秒钟,然后机器停下来。操作员走过去,花5分钟把上一摞卡取出来,放进下一摞,按下按钮。机器再跑10秒,再停。

算一下:一天24小时,机器只有不到3%的时间在真正计算,剩下97%在等着操作员换卡

一台计算机当时造价几百万美元(相当于今天的几千万),结果你花钱请它晒太阳。

这不合理。

为什么会出现这种情况?因为人的反应速度比机器慢几个数量级。机器跑一个任务只要几秒,但人工准备下一个任务要几分钟。怎么办?让机器自己接管下一个任务。

第一个站出来想办法的,不是学术大牛,而是搞应用的人。1950年代中期,美国通用汽车公司北美航空合作,为IBM701型计算机写了一个叫GM-NAA I/O的系统。它能做什么呢?自动批量加载任务、自动调用汇编程序、自动把结果打到磁带上。

这就是批处理系统的雏形。

它的核心思想极其简单:让监督程序自己从读卡机里取下一个任务,而不是让人去按按钮。

操作员只需要一次性把一摞卡放进去,然后去做别的事。监督程序跑完一个任务,自动调出下一个。中间没人闲着。

这就像给传送带装了个自动送料器。

GM-NAA I/O在1956年投入使用。它被公认为世界上第一个实锤的操作系统。虽然它还很简陋,但它证明了“常驻监督程序”这条路走得通。


二、为什么批处理之后CPU还是经常空转?——多道程序设计

批处理解决了“人工换卡太慢”的问题,但它带来了一个新问题:CPU还是经常闲着

为什么CPU会空转?因为程序不只是算,还要输入输出(I/O)。

比如你的程序要读一盒磁带。磁带的机械臂转起来,找到数据,再读进来——这个过程比CPU慢几百倍。在I/O完成之前,CPU只能干等。

单道批处理系统中,内存里只有一个程序。这个程序一发起I/O,CPU就进入空闲状态,直到I/O完成。而I/O完成的时候,下一道程序还躺在读卡机里呢——因为一次只能跑一道。

这就好比一个厨师,做一道菜等5分钟烤箱预热,然后下一道菜又要等另一个烤箱。烤箱在工作的时候,厨师站在旁边发呆。

那能不能让CPU不等呢?

比如,程序A在等读磁带的时候,CPU去跑程序B?

可以。但你需要两个东西:一是内存里能同时放多个程序;二是CPU能快速在程序之间切换。

这就是多道批处理系统

1960年代初,IBM在大型机System/360上实现了这一技术。它被称为OS/360——一个支持多道批处理的、真正意义上的操作系统。

工作流程是这样的:内存里同时驻留3-5道程序。程序A发起I/O,操作系统立刻把CPU切换给程序B。B跑着跑着也发起I/O,操作系统再切给C。当A的I/O完成时,操作系统收到一个中断信号,记下“A可以继续跑了”,等当前正在跑的程序让出CPU,再切回去。

这样一来,CPU几乎永远不会闲下来。利用率从不到10%飙升到60%以上。

这笔账在当时太划算了——操作系统本身会消耗一点CPU时间(用来做调度、处理中断),但换来的整体利用率提升,让计算机在固定硬件上多干了几倍的活。


三、为什么多道批处理还是不能跟计算机实时对话?——分时系统的诞生(CTSS与DTSS)

多道批处理虽然提高了CPU利用率,但有一个问题仍然没解决:没有交互

为什么没有交互是个大问题?因为编程本质上是试错过程。你不能实时看到结果,就不知道哪里错了,改完再试又要等几十分钟。一个下午改不了几行代码。

你还是看不到程序实时运行的结果。你提交一个程序,然后等。等了一个小时,拿到打印结果:第42行少了一个分号,编译失败。改完再提交,再等一个小时。

一个下午改了两行代码。这太折磨人了。

那么,如何让用户能和计算机实时对话?

答案是分时系统。它的核心思想是:CPU速度快到可以“骗”过人类

具体怎么骗?我们需要把“分时”的原理讲透彻。

假设你一个人用一台计算机。你敲一行命令,CPU花了0.01秒处理完,然后它就闲着,等你敲下一行命令。这9.99秒CPU都在空转,浪费了99%的计算能力。

现在换一个场景:有30个人同时用这台计算机。CPU为第1个人服务0.01秒,然后立刻切换到第2个人服务0.01秒,再切换到第3个人……如此循环。一秒钟之内,CPU可以为30个人各服务约3次(30 × 0.01秒 = 0.3秒,剩下0.7秒是切换开销)。每个用户都会觉得:计算机好像一直在为我服务——因为两次服务之间的间隔只有约0.33秒,人根本感觉不到。

这个过程叫做时间片轮转。每个用户被分配一个极短的时间片(比如1/100秒),时间片一到,操作系统强制把CPU交给下一个用户。切换得足够快,人的感觉就是“独占”了机器。

1961年,MIT(麻省理工)IBM 709计算机上实现了第一个大规模分时系统,叫CTSS。它同时支持30个用户,每个用户坐在一台电传打字机前(一种带键盘的打印机,没有屏幕),敲命令,打字机立刻咔咔打出结果。不需要打孔卡,不需要等半天。

程序员第一次可以和计算机“对话”了。这就是“交互式编程”的开端。

CTSS的成功很快催生了另一个更有影响力的系统:DTSS

1963年,达特茅斯学院的两位教授——约翰·凯梅尼和托马斯·库尔茨——想让全校近千名学生都能用上计算机。但他们只有一台GEGE 225主机。怎么办?他们写了DTSS,同时支持上百个终端。他们还发明了一门极其简单的编程语言,让普通学生也能学会——就是BASIC

DTSS加上BASIC,开启了“人人都能编程”的时代。分时系统的价值,从“提高机器利用率”变成了**“让更多人有机会使用计算机”**。

所以,分时系统被证明是可行的,而且极其重要。但MIT的野心不止于此。


四、为什么想做一个“终极分时系统”反而失败了?——Multics的教训

MIT觉得CTSS还不够强。他们想:能不能做一个更大更强、能同时服务几百个用户、还有完善的文件系统、安全机制、动态链接……的系统?

1964年,一个超级项目启动了。它叫Multics。目标是把计算变成一种utility,就像自来水或电力一样。你打开家里的终端,就能用计算机,不用管机器在哪,不用管资源怎么分配。

为此,它引入了一堆革命性设计:

  • 分层文件系统:目录可以嵌套目录。你现在用的Windows和macOS文件夹,就是从这里来的。
  • 动态链接:程序运行时才加载需要的代码库,而不是编译时全部打包。
  • 高安全性:不同用户、不同进程之间严格隔离。一个用户的程序崩溃不会拖垮整个系统。
  • 单级存储:内存和磁盘统一管理,程序员不用手动操心数据换进换出。
  • 进程间通信(IPC):不同程序之间可以交换数据。

这些特性,今天的操作系统全都有。但在1960年代中期,它们太超前了。

项目由MIT贝尔实验室通用电气联合开发。通用电气提供硬件(GE-645大型机),MIT和贝尔实验室写软件。看起来是梦幻组合,实际执行却是一地鸡毛。

为什么Multics失败了?

第一,硬件跟不上设计。GE-645的内存分页机制造成了严重的性能抖动,系统跑起来慢得没法用。第二,复杂度爆炸。每个功能都做到极致,但功能之间相互牵扯,开发进度一拖再拖。第三,目标过于宏大。在当时的硬件条件下,想要实现一个完美无缺的通用分时系统,几乎是不可能的。

1969年,贝尔实验室退出。项目负责人后来回忆说:“Multics太学术了,太复杂了,我们看不到它变成实用产品的希望。”

Multics没有彻底死掉——通用电气后来把计算机业务卖给了霍尼韦尔,霍尼韦尔继续开发,最终在1975年发布了商业版本,跑了好些年,在一些银行、大学和军事机构服役到1990年代。

但它成了一个象征:目标太宏大,设计太复杂,最终被自己的野心压垮。

Multics的哪些东西被证明不可行? 不是它的理念(那些理念后来都被实现了),而是它的一次性做到完美的方式。在1960年代的硬件条件下,那条路走不通。

哪些被证明可行? 它的思想——分层文件系统、动态链接、安全隔离、IPC——全部被后来的操作系统继承。

Multics留下了一个极其宝贵的教训不要试图一次性解决所有问题。 复杂度是工程的头号敌人。先让一个简单的东西跑起来,再慢慢加功能。

这个教训,被一个贝尔实验室的工程师死死记住了。他叫肯·汤普森。退出Multics项目后,他闲得无聊,想玩一个自己写的游戏,但找不到一台能跑它的机器。于是他决定自己写一个操作系统——一个“小而简单”的,绝对不像Multics那么复杂的系统。

这个“顺手写的玩具”,叫UNIX。那是下一章的故事。


五、为什么技术更先进的英国Atlas没有成为主流?——平行叙事与生态的力量

在讲Multics的时候,如果只讲美国,会漏掉另一个重要的早期操作系统:英国的Atlas Supervisor

1962年,英国曼彻斯特大学造了一台叫Atlas的超级计算机。它配备了当时最先进的虚拟存储技术,它的操作系统Atlas Supervisor比CTSS更早实现了虚拟内存(把磁盘当内存用,让程序觉得拥有远超实际物理内存的空间)、单级存储(程序员不区分内存和磁盘)和资源调度(多任务优先级动态分配)。

从技术上来说,Atlas Supervisor非常先进。但为什么它没有进入主流叙事?

因为Atlas只造了一台。它是学术验证机,没有商业化,没有推广到其他厂商。它的文档发表在英国计算机学会的期刊上,被少数专家读到,但没有像CTSS和Multics那样形成多家机构参与的合作开发社区。

而MIT的系统,因为有MIT、贝尔实验室、通用电气三方参与,工程师们在项目上成长起来,然后跳到IBM、DEC、HP,把分时系统的理念带到整个工业界。

这就是生态的力量。一个技术再先进,如果只有一个孤本,它就很难改变历史。而一个技术哪怕没那么完美,只要有一批人带着它到处“传教”,它就可能成为标准。

Atlas的故事告诉我们:计算机史不是“谁技术最好谁赢”。谁参与了、谁传播了、谁形成了生态——这些有时比技术本身更重要。

所以,Atlas Supervisor技术上可行,但因为没有形成生态,最终没有成为主流。


六、分时系统带来了什么编程文化转变?

讲完这么多技术,不妨停下来想想:分时系统带给世界的,到底是什么?

表面上看,是“多人同时用一台机器”。但本质上是编程范式的彻底改变

在批处理时代,编程是“提交-等待-结果”的死循环。你写一行代码,要等几个小时才知道对错。这种模式会塑造你的人格:你会变得异常谨慎,因为你错不起。你会在纸上反复推演,确保万无一失才敢提交。这不是什么美德,是被逼出来的

分时系统来了之后,你坐在终端前,敲一行命令,回车,立刻看到结果。错了?改,再试。你可以试十次,没有任何惩罚。

编程突然从“一次性的精准作业”变成了“快速迭代的探索过程”。

这种交互式编程的文化转型,影响太大了:高级语言(尤其是BASIC)可以普及,因为你可以边学边试;调试工具可以出现(比如早期的ddt),因为你可以在程序运行时停下来检查变量;屏幕编辑器成为可能,因为你看到什么就能改什么。

我们今天所有的编程习惯——写两行,跑一下,再改两行——都源于分时系统创造的环境。如果计算机一直停留在批处理阶段,软件工程不会成为一门学科,因为没有人能承受那么高的试错成本。


本章小结:哪些选择被固定了,哪些可能性被放弃了?

回到开头的问题:我们为什么需要操作系统?

  • 因为人工操作太慢 → 批处理:让机器自动接任务。
  • 因为I/O让CPU闲置 → 多道程序:让CPU切换任务,别闲着。
  • 因为没有交互 → 分时:让程序员能实时对话。
  • 因为想做终极分时系统 → Multics:太复杂,失败了。
  • 因为Multics失败 → UNIX:选择了“小即是美”。

哪些选择被固定了?

  1. 操作系统的常驻性:放弃人工控制硬件,换来自动化效率。从此操作系统是开机就运行的后台管家。

  2. 多道程序设计:放弃“一次只跑一个程序”的简单模型,换来CPU利用率飙升。所有现代操作系统都这么做。

  3. 分时交互:放弃批处理的“提交-等待”模式,换来实时对话式编程。这是个人计算机交互方式的雏形。

  4. 分层文件系统(来自Multics):放弃平面文件存储,换来树状目录结构。你今天用的文件夹就来自这里。

  5. 虚拟内存和单级存储(来自Atlas和Multics):放弃手动管理内存换入换出,换来编程便利。即使有性能代价,也值得。

  6. “小即是美”的设计哲学(来自Multics的教训):放弃一次性解决所有问题的野心,先让简单的东西跑起来再迭代。UNIX就是靠这个哲学赢的。

哪些可能性被放弃了?

  • 单道批处理:被彻底抛弃,只在极简嵌入式系统中有残存。
  • 平面文件系统:被放弃。除了某些数据库,很少有系统要求用户把所有文件放一个目录。
  • 手动内存管理(覆盖式加载):被放弃。虚拟内存成了标配。
  • Atlas式孤本技术:技术上可行,但因没有形成生态,被历史遗忘。
  • Multics式宏大设计:理念正确,但1960年代的硬件撑不起来。它的教训比它的代码更值钱。

还有一点需要特别强调:路径不是“最优解”驱动的,而是“解决当下最痛的问题”驱动的。 每个解决方案都会带来新问题,然后下一代人解决新问题。

这就是操作系统诞生的真实故事。不是英雄史诗,而是一连串的“补丁叠补丁”。但正是这些补丁,让计算机从实验室里的庞然大物,变成了每个人都能交互的工具。


下一章预告: 肯·汤普森为了玩游戏,写出了UNIX。丹尼斯·里奇发明C语言,让UNIX学会“跑”到任何机器上。然后,法律、商业和理想主义把UNIX撕成两半——一半走向封闭(System V),一半走向开源(BSD)。再然后,一个芬兰大学生写了一个“玩具内核”,不小心改变了世界。下一章,我们讲UNIX时代。