Kernighan《UNIX 传奇:历史与回忆》杂感

Brian W. Kernighan 是一个伟大的技术作家,我买了他写的几乎所有书。他近些年的书我买的是 Kindle 电子版,不占地方。

以下是我手上保存的纸版书:

陈硕手上保存的 bwk 著作

Kernighan 的书大多与别人合作,它与 P. J. Plauger 和 Rob Pike 分别合作了两本书,参见图中左上角的两本和右下角的四本。右上角是著名的 K&R,中间第一本是 AWK,这两本书的合作者 D.M. Ritchie 和 A. V. Aho 都是拿了图灵奖的人。正中间那本《风格的要素》是《英文写作指南》的原版,是它上面那本《编程风格的要素》致敬的对象。

下排中间的是裘宗燕老师翻译的《程序设计实践》,这是我上大学期间买的性价比最高的技术书,定价只有 20 元,却让大一刚学了 C 语言和数据结构的我的编程能力提升了不止一个档次。读完这本书之后,我意识到认准作者和译者是挑到好书的不二法门,并从此记住了 Kernighan 这个不太常见的名字。注意 Kernighan 中的 g 不发音,读音接近“柯尼汉”或“科尔尼汗”,不要读成“柯尼根”,以下简称 bwk,三字母用户名是 Unix 先锋人物的殊荣 //youtu.be/Y4lDvkAFyps


我的书架上专门有一格叫 Kernighan Classics。

上大三的时候,我又发现了 bwk 在普林斯顿开设的两门课:面向大一新生的秋季 COS 109 课程和面向高年级本科生的春季 COS 333 课程《高级编程技巧》,感觉如获至宝。特别是 COS 333 让我眼界大开,深刻体会到了自己在动手能力上的差距。

《Unix 传奇:历史与回忆》封面

《Unix 传奇:历史与回忆》 是 bwk 2019 年的新作,我 2020 年 1 月购得,先通读了英文版,9 月份机缘巧合做了中译本的审校,逐字阅读了韩磊的译本,乘着记忆尚未褪去,写一篇书评兼读后感。在谈这本书之前,让我先聊几句 Unix。Unix 的主要故事发生在上个世纪 70 ~ 90 年代,因此后文所有的“年代”都是二十世纪,不再赘述。

Unix 最初是“草根”操作系统

“UNIX is very simple, it just needs a genius to understand its simplicity.” — Dennis Ritchie

Bell Labs 的 Ken Thompson 和 Dennis Ritchie 在 70 年代初写了 Unix,根据传统,下文简称 Ken 和 dmr。

Unix 一开始并不是为高端的价值几百万美元的大型计算机而开发,它最初诞生在售价“仅有”几万美元的小型机上。介绍 Unix 的经典论文《The UNIX Time-Sharing System》发表在 1974 年第 7 期的《ACM 通讯》杂志上。在文章的第 1 节有这么一段话,我标一下重点:

Perhaps the most important achievement of Unix is to demonstrate that a powerful operating system for interactive use need not be expensive either in equipment or in human effort: it can run on hardware costing as little as $40,000, and less than two man-years were spent on the main system software. We hope, however, that users find that the most important characteristics of the system are its simplicity, elegance, and ease of use. — //www.bell-labs.com/usr/dmr/www/cacm.html

本文把最初 Ken 在 PDP-7 开发的那个操作系统叫做 Unics,把后来 Ken 和 dmr 在 PDP-11 上重新开发的叫 Unix,以示区别。PDP-7 是字长 18-bit 的小型机,有 8K x 18-bit 内存(约 16KB),Unics 使用其中 4K 字,剩下 4K 留给用户程序;Unix V1 运行在 PDP-11/20 上,它是 16-bit 小型机,内存有 24K 字节,Unix 内核使用其中 16KB,剩下 8KB 留给用户程序。这些初代 PDP 小型机的性能估计还比不上 80 年代初上市的 IBM PC 机(基于 16-bit 的 Intel 8088 CPU),恐怕跟任天堂红白机(8-bit 6502 CPU)相比也快不了太多。我估计高端 PDP-11 的性能和 Intel 80286 相当,大致也就是跟 80 年代的 x86 个人电脑打个平手。

BYTE in 1984 reported that the PC’s Intel 8088 microprocessor outperformed the PDP-11/23 when running Unix.
//en.wikipedia.org/wiki/PDP-11#Decline

运行 Unix 并不需要比 MS-DOS 更高档的机器,我实在不明白为什么微软要自己搞一套这么原始的“PC 磁盘操作系统”,跟 Unix 比起来,称 MS-DOS 是“操作系统”真是太抬举它了。

MS-DOS was a pretty pathetic operating system. — Brian Kernighan //youtu.be/O9upVbGSBFo?t=2421

PDP-7 长这个样子:
PDP-7
图片来源://en.wikipedia.org/wiki/Ken_Thompson

站着的 dmr、坐着打字的 Ken 和几台 PDP-11:
Ken和dmr
图片来源://www.bell-labs.com/usr/dmr/www/picture.html

在 60~70 年代,高端计算机的代表有 CDC 6600(60-bit)、 IBM 7094/360/370 系列(36-bit 或 32-bit)、 Clay-1 (64-bit)等等,它们的售价数百万美元起,折合今天上千万美元一台,也就是人民币上亿元,运行着科学计算和“海量”数据处理等关键任务。与之对比,16-bit 的 PDP-11 小型机的价格只有这些大家伙的百分之一,Unix 最初定位是面向程序员的交互式操作系统,其核心功能(卖点)是文档制备(document preparation),说白了就是排版打字,核心业务和 90 年代国内街头常见的电脑打字铺子高度重合。70 年代的科研院所没有认真对待这种运行在“低端”设备上的、很长时间没有商业支持的“hobbyist”操作系统是完全可以理解的。但是,Unix 靠着群众路线,走农村包围城市的道路,最终鲤鱼跃龙门,成就一代霸主地位,把以前那些大家伙们扫进了历史的垃圾堆。由于 Unix 售价低廉,对大学等教育机构只收几百美元的工本费(磁带和邮寄),还附带完整源码和详细的程序员手册,大约从 1975 年开始,它开始在大学中流传,在学生中占领了思想阵地,大家认为在 Unix 上写代码或改进 Unix 系统是很酷的事情,有无数的毕业论文以此为题(下文提及的 Marshall Kirk McKusick 博士即是一例),然后随着这些学生毕业进入工业界,也慢慢把 Unix 带入了各大公司。这个故事在这本《Unix 传奇:历史与回忆》里有生动的论述,我就不剧透了。

惯性的力量是强大的,2000 年起 Linux 在服务器领域逐渐取代 Unix 其实也是靠着类似的惯性 //www.zhihu.com/question/19738282 。公司初创的时候买不起高端的 Unix 服务器,拿 PC 机装个免费的 Linux 就能开展业务。等到业务量大起来了,往往选择买更强大的 PC 服务器,继续运行 Linux,而不是迁移到 Unix。如此新陈代谢下来,Linux 市场份额越来越大。另外一个数据:从 2018 年起,Top 500 的超级计算机全部都是 Linux 系统。

甚至与目前大家对 Unix 的印象相悖,Unix 一开始也不是安全、可靠、高性能的代名词。1988 年世界上第一个通过因特网传播的计算机病毒 Morris 蠕虫 感染了全球 1/10 的联网 BSD Unix 主机。Marshall Kirk McKusick 等人在 1984 年发表的经典论文《A Fast File System for UNIX》中提到,传统的 Unix V7 文件系统只能发挥 2% 的磁盘最大带宽,也就是 20KB/s,比软盘快不了多少。而他实现的 Berkeley 快速文件系统(FFS),提高了可靠性,还把性能提高了 10 倍以上,即便如此,也只发挥了 50% 磁盘带宽,有兴趣的读者可以听 Dr. McKusick 自己讲这个故事。我还听说一些商业公司的例子,这里就暂且按下不表了。

Unix 早期历史

最早 PDP-7 上的 Unics 内核是 Ken 一个人写的,之后 dmr 加入一起开发了 PDP-11 上的 Unix,并同时负责 C 编译器的开发;可以说,早期的 Unix 内核是 Ken 和 dmr 的“二人转”,从 V4 到 V6 的内核源码有两个子目录,ken 和 dmr,分别存放二人各自维护的源文件。到了 V7 才根据功能划分——而非源码作者——组织内核源文件。

Unix 的诞生可以说是机缘巧合,在正确的时间出现在了正确的地方,//youtu.be/EY6q5dv_B-o 有 Ken Thompson 在 2019 年 5 月自己亲口讲述这个小故事。注意,有人把这个故事误传为 Ken 花 3 周写出来了 Unix,这是理解错误。Three weeks away from an OS,是说 Ken 花 3 周写了一个编辑器、一个汇编器、一个 shell,这样就把 Unix 空缺的部分填上了,而 Unix 内核在这之前就已经写好了。我总结就是 Bell Labs “有钱又有闲”。Bell Labs 当时属于 AT&T 公司,由于 AT&T 垄断了美国全国的电话业务,“收电话税”富得流油,Bell Labs 也资金充足。在 PDP-7 上写了 Unics 之后,Ken 纠结了几个人一起忽悠领导买了一台名义上用于打印专利申请表的 PDP-11,实际上用它来继续搞操作系统开发。另一方面,也正因为 AT&T 的垄断地位,其受政府的严格监管,经营范围不能涉及销售计算机软件(含操作系统),Unix 才可以以接近免费的价格“开源”给大学,并且开发由 Ken 和 dmr 这样的绝顶程序员主导。假如 Unix 一开始就是商业产品,我猜这个传奇就不会发生了:一是价格不会那么低,用户群不会这么大;二是从知识产权保护的角度,估计也不会提供源码;三是会为了增加销量而实现甲方种种不合理需求,不会保持简洁优雅的高品味。

我把《Unix 传奇:历史与回忆》的时间线整理成下表:

版本 发布日期 内核行数 目标大小 主要改动
PDP-7 Unics 1970-01 3,000 汇编 单用户
第 1 版 Unix PDP-11/20 1971-01 4,700 汇编 文档排版工具 roff
第 2 版 Unix 1971-11 ??? 缺失 首次提供 C 编译器、新的排版工具 nroff
第 3 版 Unix 1972-06 ??? 缺失 多用户?管道、Yacc
第 4 版 Unix PDP-11/45 1973-11 6,500 C 和 600 汇编 内核改用 C 语言重写,CACM 1974论文。troff
第 5 版 Unix PDP-11/40 1974-06 7,600 C 和 1,100 汇编 25KB 开始进入大学。C 语法把 =+ 换成 +=,已经很接近现代版本。
第 6 版 Unix PDP-11/70 1975-05 10,500 C 和 1,700 汇编 28KB 《莱昂氏UNIX源代码分析》、日本人写的《Unix内核源码剖析》、国人写的《返璞归真——UNIX技术内幕》;MIT 的现代克隆 xv6。C 语言新增 long 类型。
PWB/Unix 1977-07 10,000 C 和 1,000 汇编 lex、make。C 语言新增 unsigned、union、typedef 关键字。
移植 Interdata 7/32 1978 9,000 C 和 3,200 汇编 52KB 澳大利亚的卧龙岗大学把 v6 移植到了新的 32-bit 硬件平台。
第 7 版 Unix 1979-01 17,000 C 和 2,100 汇编 51KB 第一个便于移植的版本,awk、pcc、tar。C 语言新增short、enum 关键字。
32V Unix 1979-05 14,700 C 和 1,200 汇编 59KB V7 首次移植到 VAX-11/780,但没有使用分页式虚拟内存。
System III 1980-06 17,800 C 和 1,600 汇编 第一个有商业支持的版本

表中的发布日期和内核源码行数来自://minnie.tuhs.org/cgi-bin/utree.pl

搁在今天,以早期 Unix 内核的代码量和复杂度而论,估计会被归入嵌入式操作系统或者微控制器上的实时操作系统。根据 Andrew S. Tanenbaum 在 //www.cs.vu.nl/~ast/brown/ 的观察,优秀的个人程序员可以独立实现早期 Unix 内核的完整功能,他举了几个例子,包括:

  • 30岁的 Ken 和 32 岁的 dmr 在 1973 年夏天用 C 语言重写了 Unix 内核,即 Unix v4;
  • 30 多岁的 Douglas Comer 在 1981 年发布了 XINU;
  • 43 岁的 Andrew Tanenbaum 在 1987 年发布了 Minix 1.0(花了他用 3 年业余时间),然后与人合作在 1997 年发布了 Minix 2.0;
  • 不满 22 岁的 Linus Torvalds 在 1991 年 9 月发布了 Linux 0.01 (开发用了不到一年时间)。跟前三个最初都是面向 16-bit 硬件有所不同,Linux 0.01 直接在 32-bit 的 80386 上开发。

我估计进入 2010 年之后,实现 Unix v6 这种级别的操作系统的工作量可以当本科生的毕业设计,但当不了硕士的毕业论文。

当然,这里边要数 Ken 和 dmr 首创 Unix 的含金量最高,后面的跟风之作只能算 Unix-clone,毕竟模仿是最大的恭维。Ken 和 dmr 首次完成了用高级语言实现操作系统的创举,并“年纪轻轻”就获得了 1983 年的图灵奖(获奖的时候二人只有 40 岁出头,而在 40 岁之前获得图灵奖的目前只有 Donald Knuth 和 Robert Tarjan 两人)。在 Unix 之前,操作系统都是用汇编语言写的,针对特定硬件平台,不可移植,“拿高级语言写操作系统”会被当成疯子;在 Unix 之后,我不知道哪个主流操作系统(MS-DOS 除外)不是主要用 C 写的。可以说 Unix 重新定义了“操作系统”,就凭这一点就足以永载史册。

TCP/IP 也有类似的情况,Vinton Cerf 和 Robert Kahn 凭借在 1974 年设计了 TCP/IP 获得了 2004 年图灵奖,他们的论文《A Protocol for Packet Network Intercommunication》其实与后来 1981 年 9 月发布的 RFC 793 定稿在细节上有不小的出入,但首创之功属于他二位。 Bill Joy 于 1982 年左右在 4.2BSD Unix 上实现了第一个广为使用的 TCP/IP 协议栈,后来创建了 Sun 公司,成了亿万富翁。Van Jacobson 在 1988 年成功提出了 TCP 拥塞控制,解决了当年的大面积网络瘫痪问题,他于 2012 年成为 Internet 名人堂 的创始成员。适合嵌入式系统的 lwIP 是 Adam Dunkels 2001 年的硕士论文。而到了 2020s,实现一个玩具级的 TCP/IP 已经降级为大学本科编程大作业的内容 //cs144.github.io

参考资料

这本《Unix 传奇:历史与回忆》当然是最好的参考文献,是当事人回忆的一手资料。另外也可交叉印证以下内容。

Unix 的遗产

上大学的时侯有一阵我对各种“底层实现”产生了比较浓厚的兴趣,但事实证明钻研古代 Unix 源码的性价比不高。我先是囫囵吞枣读了 CACM 1974 年那篇经典论文,然后不自量力试图去读《莱昂氏UNIX源代码分析》,结果只大致读懂了 malloc 和 printf 这两个基础库函数的实现,后面操作系统内核的实际内容由于缺乏对 PDP-11 的理解实在读不下去,只好半途而废。记得还从图书馆借阅过浙江大学胡希明老师编著的《Unix 结构分析》,这恐怕是全球惟一一本对 Unix System V 做源码分析的书(System V 至今没有正式开源)。第一部分文件系统的实现(一次间接、二次间接)还勉强能跟上,第二部分开始讲 VAX-11/780 上的内存管理,又让我放弃了。我认为一头扎进工业级的源码去学习是非常低效的,只能算是没有办法的办法。我当年在 tuhs.org 上漫无目的地看 Unix 源代码,除了让我感叹 C 语言这么多年没啥变化之外,也没学到啥有用的知识,现在只记得有一处 C 语言的用法让我记忆犹新:位于 //minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/sys/sys/prf.c 的 printn() 函数,打印 b 进制的整数 n,其中最后一句是:

    putchar("0123456789ABCDEF"[(int)(n%b)]);

我当时就觉得没有必要花时间去弄懂 PDP-11 和 VAX-11 这种比我年龄还大的早已被淘汰的机型,现在就更不必说了。因此我建议对 Unix v6 有兴趣的读者可以去看 MIT 的人在 x86 上重新实现的 xv6,代码量约一万行。xv6 适当简化以突出重点,学习的性价比较高。

我上本科的时候,学院服务器机房有一台 Sun E450 服务器,四四方方的一个蓝灰色大铁块(见下图),据说挺沉,反正我看见机箱下面还自带轱辘。此物被老师们当宝贝一样供着,我们小本没有上机(远程登录)资格,因此我至今也不知道这台机器的软硬件具体配置。刚上研究生时,我在实验室角落找到了两台落灰闲置的 Sun SPARCstation 20,重新装上新版的 Solaris 之后,把玩了几周。用下来感觉这台 1994 年上市的 Unix 图形工作站的性能比不上 1997 年国内风靡一时的 Intel Pentium 133。眼见 Intel 迎头赶上,Unix 的领先优势已经所剩无几。

Sun E450 server

图片来源://en.wikipedia.org/wiki/Sun_Enterprise

我记得大三有一次课后作业,老师让调研工作站和小型机的软硬件配置,让我对 Unix 的衰退有了直观的认识。90 年代可以说是 Unix 最繁荣的时代,各大高端硬件厂商都有自己的 Unix 和 CPU 体系结构,并有对应的服务器和工作站产品线,除此之外,还有运行在 Intel x86 上的商用或免费 Unix。

Unix 阵营 CPU 工作站
IBM AIX POWER RS/6000
HP-UX PA-RISC 和 Itanium HP 9000
SGI IRIX MIPS SGI Indigo
Sun Solaris UltraSparc Ultra 系列

进入 21 世纪,x86 扩展成了 x86-64,PC 机也能用上 4GB 以上的内存,Unix 工作站随之消亡;而中低端服务器市场迅速同质化,Intel Xeon + Linux 一统江湖,实现了对 Unix 的逆袭。也因为如此,可移植操作系统界面(POSIX)标准的意义也大为减弱,它要解决的问题已经消失,程序在不同 Unix 之间的可移植性也变得不那么重要了。

互联网向用户提供免费服务,需要用最少的钱支持尽量多的并发用户,那么选用廉价的 Intel x86 服务器搭配免费的操作系统是自然的选择,而 Unix 的卖点(安全、稳定、可靠)显得不那么重要了。毕竟因特网本身也没那么可靠嘛,网站访问出错多刷新几次就好了,谁知道是网络的问题还是网站服务器的问题呢?我的第一份工作是在一家成立于二战以前的跨国金融公司,原本以为会遇到小型机,结果进去一看,只有一些 legacy 系统还运行在跑着 Solaris 的 Sun Enterprise 服务器上,新的业务清一色用 RedHat Enterprise Linux 跑在 x86-64 的刀片服务器上。我的同事 Kevin 从华为跳槽过来,据他说电信的计费系统这样的关键业务也跑在 Linux 上。用一句话形容我的直观感受:Unix 已死,有事烧纸。我想有人不同意“Unix 已死”的判断,没关系,也不必试图拿 FreeBSD、macOS、illumos 来说服我,真的。

我认为 Unix 最重要的遗产有两点:

  • C 语言
  • 示范了操作系统的接口应该是什么样子的

C 语言是有史以来最重要的编程语言,是整个现代信息社会的基石。在 Unix/C 诞生的那个年代,字节的长度还不统一,有 6/7/8/9-bit 等多种可能。6-bit 的字节无法区分大小写字母(在字长 18-bit 的机器上每个 word 刚好存 3 个字符 ),在 C 之前发明的语言大多是不区分大小写的,例如 Fortran、Pascal、SQL、BASIC 等等,而 C 之后的语言基本都区分大小写了:C++、Java、Python 等等,这估计不是一个巧合。进入 80 年代,随着 TCP/IP 的普及,字节的长度也很快统一到了 8-bit,因为其他字长的机器很难方便地与 Internet hosts 通信。开个脑洞,如果 Unix 没有转到 PDP-11(16-bit 字长,可按 8-bit 字节寻址),而是继续在 PDP-7(18-bit 字长)开发,我们今天的 IP 地址会不会是 36-bit?(就像 a.b.c.d.e.f,其中 0 <= a,b,c,d,e,f < 64。)

C 语言也影响了通用 CPU 硬件的发展路线,80 年代起,设计一个新 CPU 指令集的时候就必须考虑能不能高效地表达 C 语言,因为只要支持了 C 语言,就有无数的软件包可以方便地移植过来。可以说,C 语言定义了计算机处理器应该具备的基本功能。而那些与 C 语言不太兼容的特性就慢慢没人用了,例如 16-bit x86 上的分段式内存管理在 32-bit 系统上被基本闲置,到了 x86-64 时代就废弃了(防杠:听说虚拟化的场合还用得到)。

2011 年 10 月 C 语言之父 dmr 去世,我很喜欢这个关于他侄儿的小故事:
//medium.com/@wilshipley/the-absolutely-true-story-of-a-real-programmer-who-never-learned-c-210e43a1498b

Unix 另一个重要的遗产:定义了操作系统的接口。可以说,Unix 提供了一种语言(不是一般意义上的编程语言),这门语言的名词(主语和宾语)主要是文件进程,它的动词(谓语)是各种系统调用。

xv6 把 Unix v6 的系统调用从 50 来个精简到了 20 个,只要实现了这 20 个系统调用,你就有了一个具备层次化文件系统的多任务操作系统。这些系统调用很多是和文件相关:creat/open/close/read/write/seek/stat/unlink 这十来个系统调用就支持了常用文件操作。其他一些可以按字节读写的东西——比如 pipe、TCP/UDP sockets——也可以用这套接口来操作,不必再发明新的动词。Unix 的文件这个概念更接近一般意义下的字节流,比“磁盘文件”的范围要广。Unix 号称一切都是文件,除了按字节读写,更重是要能 poll,这样可以用一个统一的框架来处理各种事件。当然,话不能说太满 。提到 Unix 文件系统,inode 是个绕不开的概念,//www.zhihu.com/question/58261869/answer/156276161 。理解进程的文件描述符表、系统的打开文件表、代表磁盘文件的 inode 表这三个表之间的引用关系 (//chenshuo.com/notes/kernel/file-descriptor-table/),这对理解 Unix 文件至关重要。文件的长度和打开文件的偏移量为什么不存放在一起?同一个磁盘文件,一个进程 open 它两次,拿到两个 fd;或者 open 一次,再 dup 一次拿到两个 fd,这两种情况在读写的时候有何区别?普通文件的 inode 有什么内容,为什么文件名不在里边?

文件是静态的,进程是动态的,理解起来可能要稍微难一些。进程是运行着的程序,理解进程对于理解现代操作系统至关重要。一个系统上可以同时有多个进程在运行,每个进程有自己独立的(虚拟)地址空间,同一个可执行文件可以起多个进程,这些进程通常共享代码段,但有各自的数据段。在一些早期的书上,甚至把进程当虚拟机来看待,不过这种讲法随着“虚拟机”概念的转移已经很少见了。

不过,Unix 的 fork/exec/wait/kill 这套管理进程的系统调用在多线程时代显得有些过时,我比较同意微软的人写的这篇文章:《A fork() in the road》

这套“操作系统语言/思想”被 Linux 很好地继承和发展,因此 Eric Raymond《Unix 编程艺术》仍然值得一读。

2019 年 10 月,Bell Labs 搞了一个庆祝 Unix 诞生 50 年的纪念活动,视频://youtu.be/l03CF9_078I 。注意 20:42 可以看到坐在观众席里的 C++ 之父 Bjarne Stroustrup,他后来上台讲一段话。

《Unix 传奇:历史与回忆》是一本有趣的闲书

《Unix 传奇:历史与回忆》是一本故事书,想从中学习具体的 Unix 编程技术无异于缘木求鱼。它是面向非程序员的书,其中出现了 void main() 这样的谭浩强式 C 语言写法,但愿不要有人拿这当例子说明 void main() 是对的——“你看大名鼎鼎的 Kernighan 自己都这么写哦!”。这本书讲了很多人和事,历史总是不断重复的,书上的故事情节竟然也在自己身边发生着,让人不禁感叹太阳底下没有新鲜事。

译者韩磊先生与我相识多年,他文字功力深厚,常年笔耕不辍,技术水平又高,同时还具备丰富的翻译经验,这本书的翻译质量实属一流水准。这里边其实也有 bwk 自己的功劳,他老人家有丰富的写作和“被”翻译经验,英文非常好懂,而且对非英语母语的人也相当友好,我感觉这本书可能刻意避免了一些俚语与俏皮话——他知道哪些说法容易让外国人读不懂或误解。如果你像我一样对技术的来龙去脉感兴趣,愿意花一个周末的时间读这么一本讲述 Unix 50 年兴衰史的书,合卷之后感叹一下天下大势,合久必分,分久必合,也算不虚此行。

附:贝尔实验室计算机研究中心的人员去向 //www.spinroot.com/gerard/1127_alumni.html

本文欢迎转载。由于我人在国外,没有国内的手机号,在其他网站(知乎、豆瓣)都不能发帖或回帖,就独家发在博客园好了。