一般来说,实体机器由可活动的物质部件构成。设计者们常常会根据其功能去命名它们,如:割草机、开瓶器、咖啡研磨机。它们的形状设计和构造各不相同,利用的是不同的物理定律。但它们也有共同之处:拥有相同名字的机器都在某种程度上做着与名字的描述相差无几的工作。它们基本上都能满足使用者的需求,可能有些会稍微好用一点儿。有私家庭院的人会挑选一款噪音相对较小的割草机,小咖啡馆的老板则更需要那种能精确研磨出不同粗细粉粒的咖啡机,尽管它操作起来非常复杂。有些机器是多功能的,比如一把电钻,插上不同的附件就能变成一把电锯或是一部打磨器。
计算机与这个类似,不同的是它不仅能按要求做几件不同的事,它甚至能做成千上万件事。而且,它也不需要插上不同的附件,你只要点开不同的程序,即点开一串串由0和1组成的超长数字,就能让计算机内部实现一些必要的切换,从而转换成不同的装置去完成不同的工作。每套装置系统都是一台单独的小机器,没有齿轮、轴承、电线或者滑轮,这就是模拟机,“构成它们的是指令”。不像和面团、压纸浆或者造钢坯,计算机处理的只有信息。
所以,对于计算机来说,指令就是那些齿轮和滑轮。所有的信息都要转换成二进制代码0和1,它们是计算机能够和需要“读录”的唯一代码。印在芯片上的电路会数以万亿计地分流0和1这些代码,逻辑门不断地开合,将信息流输送到这条或者那条电路,并以这种方法来下达指令。计算机上唯一“可移动的部件”是硬件上数百万的小空位,它们可以在1态和0态之间任意切换。至于计算机在某一时刻具体是一台具有何种功能的机器,则取决于数千个至数百万个微型元件的设置。
若一台实体机的各部分相互配合可以呈现许多不同的状态,那它就具备极强的可塑性,只需要在其上施加一套特殊的指令,就能把它变成一部虚拟机。由于虚拟机处理的是信息,那么它就能够与实体计算机做相同的工作:后者中的“可移动部件”只是硬件中的状态变化,而前者可以直接操纵状态变化来代表那些“可移动部件”。这也不难理解:你可以在一张纸上用铅笔演算一个长除法,但如果足够熟练,你也可以“在头脑中”进行这种运算,即通过想象,在脑海中的纸张或者黑板上书写过程。两者都会收到很好的效果,原因是,在面对这类情况时,我们想要得到的答案只是一种信息。相比之下,想象出的一个火腿三明治是不能用来充饥的,你得真的去做一个。计算机十分擅长在“头脑中”处理信息事务,所以我们有时真的分不清自己在使用和操作的到底是一台处理专项信息的“专用”“硬连线”机,还是一部在多用途芯片上运行的虚拟机。
今天,几乎所有的升降机、空调,还包括你的汽车、电冰箱和电视机遥控器里,都有那种微小、廉价的计算机芯片,它们实际上就是一些多功能计算机,能运行你笔记本电脑里操作的所有程序。但我们却选择让它们倾其一生只运行刻录在只读存储器上的一个简单的程序,将它们所有杰出的能力都封锁在那一两个技能上,例如点火控制或者周期除霜,等等。原因是,比起去制作那种只负责专项工作的专用芯片,这样做的成本要低多了。
虚拟机的概念是计算机科学中出现的一个最有用的想象支架,在计算机界,这早已人尽皆知。现在,到了将它引入其他领域的时候了。因为要从广义上使用虚拟机这个词(我会在适当的地方说明原因),所以我们有必要先了解一下它最初的意思,也就是说它本身的意思。“虚拟机”是计算机科学家杰拉尔德·波佩克(Gerald Popek)和罗伯特·戈德堡(Robert Goldberg)在1974年引入的一个概念,它最初表示的是“实体机的一种独立有效的复制品”,即各种指令的一种复制品。实体机是实在的硬件,由硅芯片和电线之类的东西组成,我们称它为A。而虚拟机是运行在另一台实体机B上的计算机程序,它能完美地模拟硬件A:速度可能会慢点,毕竟它要首先保障自己硬件上的基本操作有效运行,才能组织起硬件A上的那些操作,但的确都是同样的程序。如果你写了一个在硬件A上运行的程序,那么硬件B在运行模拟硬件A的虚拟机时,该程序应该能在硬件B上畅通无阻地运行。
这是一个非常有用的方法。部分原因是,它显然可以让一些资源免于浪费:假设这里有很多只能在Mac上运行的软件,但是如果你没有Mac,它们就无法使用。这时,如果可以在PC上编写出一个模拟Mac的虚拟机,然后成功运行,那么你电脑上的这些Mac软件就都可以运行了。你的电脑会“假装”认定它是真的Mac,而那些软件则根本就浑然不知!试想一下,一个人胳膊骨折了,然后打上了石膏。石膏可以让骨折处不再活动,而它的重量和形状会让受伤者身体其他部分的动作产生一些相应的调整。现在,有个小丑想要模仿这个手臂上打着石膏的人,如果他技艺足够精湛,他就一定会让自己的肢体行动做出一些相应的调整,“显而易见”的是:他胳膊上打着石膏呢!如此说来,那些运行软件和我们这些旁观者可能就真的看不出此时是一台在运行Mac虚拟机的PC还是一台真正的Mac。
但现实与上面的例子却多少有些出入。虽然人们已经开发出了PC上可运行的Mac虚拟机,但据我所知,这个软件并没有宣传的那么可靠。另一方面,Mac却已经有了一个简单易行又非常可靠的虚拟机,它可以运行PC的操作系统Windows,借用它,Mac持有者可以运行所有自己喜欢的Windows软件。目前,绝大多数编写出的程序都需要专门的操作系统而不是专门的硬件,而相同的硬件上可以运行不同的操作系统。所以,虚拟机的概念还需要继续扩展,还应该包括对操作系统的虚拟模仿。一种操作系统本身就是一部虚拟机,它能让一个程序在略有差异的硬件上同样有效地运行。但一个操作系统毕竟只是一种软件,并没有模拟任何实际存在的硬件,它只是按照实际要求创建出虚构的机器,遵守相关的规定、接收特定的输入等等。
Java虚拟机(Java Virtual Machine,即JVM)已成为当今最流行的一种虚拟机,这是我们扩展虚拟机概念的又一个原因。Java虚拟机不是对任何一种实体硬件机器的模仿,它只作为软件机而存在,比较像一个操作系统。可以说,是Java的出现让今天的因特网变得如此丰富多彩。有了它,你可以从网站上下载一些小程序(Java的应用小程序),让你能够填纵横字谜、玩数独、探索地图、放大照片、与世界各地的玩家一起参加探险游戏。当然,它也能处理很多“严肃”的事务。用Java语言编写程序的网站不需要在意浏览网站的用户手上拿的到底是PC、Mac还是运行Linux操作系统的计算机。因为Java程序只在Java虚拟机上运行,而PC、Mac以及Linux操作系统上都有各自专门的Java虚拟机,匹配的Java虚拟机会自动下载到你的电脑上,几秒钟便可以安装完成。然后,各种Java小程序就都能运行了,犹如魔法一般。可能你有时会注意到Java更新正下载到电脑上,也可能你注意不到。理想状态下,你不用记住自己电脑上安装的是哪一款Java虚拟机,随意浏览网站就可以了,有时网站上的Java小程序能顺利在你的电脑里运行,而不能运行时匹配的Java升级软件就会自动下载安装,以确保能够继续运行。
从我说的这些虚拟机的扩展意义出发,我们可以看到,几乎所有的计算机程序都是虚拟机,因为它们都是由一系列指令构成的软件,一旦开始运行,就将通用计算机转变成了专用计算机,而这种专用计算机本可以专门设计并建造成专门的硬件。“通用”计算机,即今天我们所说的通用图灵机理念的提出,是阿兰·图灵为科学、也是为20世纪中期以来的人类文明做出的一项最杰出的贡献。只需要在上面简单地安装和运行程序,我们就能把它转化成任意一种功能清晰的计算机!(为了防止你想跳过这一部分,我在24章中已详细介绍过了。)你不用再去组装其他的硬件计算机,有一台就足够了,剩下的事情就交给软件吧。图灵机时代的开启让我们实现了一个非凡的想法:只要有一个大块头的硬件,在里面安装无数可塑可调的“记忆”盒子或者寄存器,把需要的指令放进这些记忆盒子里,让它们运行,这样你就把这个大块头的硬件变成了你想要的任何一种计算机。
图灵机,或是笔记本电脑,只能一条一条地执行指令。我们在这个基础上扩展出了“并行”计算机的概念,它可以一次执行多条甚至数百万条指令。硬件中的任何一个地方,只要它们本身保持着一种状态,收到指令后会变成另一种状态或者不变,那这个地方就是寄存器。这种状态可以是你电脑中一个比特的0态或1态,但不限于两种状态。以这种状态为基础,任何寄存器系统都可以完成一些特定的基础操作。例如,通过让寄存器由一种状态变为另一种状态,或者用寄存器的某一种状态判定下一步的操作,寄存器系统就可以按照“计算一个函数”或者“运行一个程序”来配置自己的各个寄存器。所以任意硬件上都可以运行利用了上述基本步骤的虚拟机。一种技巧可以使用一次就可以使用第二次、第三次、更多次,在硬件上部署一部虚拟机,虚拟机中可以再部署一部虚拟机,在其中再部署一部虚拟机……
请考虑一个下国际象棋的程序,它由Common Lisp这种高级计算机语言写成,在一台PC上运行的Windows7操作系统上运行。事实上,这台PC佯装成了一台Windows机器,这台Windows机器又佯装成了一台Lisp机,这台Lisp机又佯装成了一台国际象棋游戏机。对于那些谙熟计算机或者国际象棋的观察者来说,要是从最上面一层观察的话,这个程序的诸多细节还多少可以理解(“啊哈,这个子程序生成了所有移动“象”的合法走法,然后调用另一个子程序来评估每一步……”)。然而,要是让他们去看这个程序实际的机器代码,看着那一串串0和1被吃进硬件的指令寄存器,这倒十足成了一个让人抓狂的好办法。所以,还是让我们把注意力放在那些较高的层次上吧。
其实,无论在哪一层次上,我们都只能只见森林不见树木,较低级层次上的那些细节总是很容易忽略。计算机上虚拟机的层层嵌套和关乎心智的小人儿功能主义中小人儿的层层嵌套,两者之间的雷同并非巧合。虚拟机推动着人类的创造和理解,实质性地完成了一些至今都超越我们想象的任务,比如完成航线预定、下象棋、预测天气、做记录等等,这些惊人的成就鼓励着我们:如果对大脑也采用类似(仅仅是类似)的技巧来实施逆向工程,或许我们也能得到一些收获。
在面对“说法语的人的大脑之间的相似性”这个问题时,排除解剖学上那些显著的差异,也许利用虚拟机的例子能为我们展示出一种最好的解释:所有说法语的人都具备某种版本的法语虚拟机,它藏身于他们大脑数以亿计的寄存器中,是一套由细微的习性和连锁装置构成的系统。说英语的人的大脑里同样也有这么一套固定模式的系统,即英语虚拟机。当你对一个法国人说,“Donnez-moi le sel, s'il vous plait.(请把盐递给我)”你基本上就能预见到法语虚拟机会作出的反应,因为这种反应与你,这样一个说英语的人为自己脑中的英语虚拟机输入“Please pass me the salt.(请把盐递给我)”时所给出的反应是一致的。但现在的问题是,要怎样在人类的大脑中建立起一个法语虚拟机或者英语虚拟机?
人们在下棋或是在说法语时,大脑各个不同的层面上到底都发生了一些什么样的活动,到目前为止我们还不得而知。(42)毫无疑问,我们对此给不出什么精确的描绘,不像是编译器,这种程序可以将高层指令翻译成可在硬件上运行的代码,只要计算机程序员能在最高层面上设计出一个想法,它就有把握吐出一个可执行的程序来。这里出现了一个非常重要的概念验证:至少我们找到了一种方法,它能够清楚地道出“具有数万亿活动部件的计算机,它的那种高等能力到底是什么”,而无需动用神奇组织。