近日,Andrew Binstock和Donald Knuth对一些话题进行了交流,包括开源代码运动,极限编程,多核架构,可重用代码,以及Knuth自己编程时使用的工具等。
Andrew:无论你当初并是否意识到了,你其实都是开源代码运动的发起者之一。你以前就声明过将TeX作为开源代码项目发布,原因在于考虑到当时专有现实(proprietaryimplementations)的问题,并且希望邀请更多的人来修改代码中的错误——这些都是今天开源代码项目关键的驱动力。你为开源项目从那时起的成功惊讶过么?
Donald:或许开源代码的成功是过去几十年中计算机领域里唯一没有使我惊讶的事。但是开源运动还没有发挥出全部的潜力;我相信在整个产业经济越来越多地从产品转移到服务上的过程中,开源程序将完全占领支配地位,同时会有越来越多的志愿者会参与改进代码的质量。
例如,开源代码能带来数以千计的二进制包,可以完美地针对每个独立用户进行配置,但是商业软件通常只有几种版本。一个通用的二进制可执行文件必须包含很多指令来“抹平”不同运行环境间的差异,这对于很多安装环境来说并不合适;然而源代码是高度可配置的,因此这种浪费也就随之消失了。这是开源软件的巨大优势。
但是我认为有少数软件,比如Adobe公司的Photoshop,够能比它开源的竞争者更优秀(比如Gimp)——由于某些原因,我真的不知道为什么!我非常乐意花很多钱去买真正好的软件,前提是我确认它出自最佳的程序员之手。
不过请记住,我对于经济问题的观点非常不可靠,因为我只是个教育者和科学家。我对于市场几乎一无所知。
Andrew:我听说你曾经参加过一次在斯坦福举办的编程大赛,你最终提交的那个获奖的作品,只经过一次编译就能正确运行了。这件事是真的么?在软件领域里,当今的开发者需要频繁地构建程序,每次只增加很少量的代码,过程中要依赖即时编译技术,并且要创建并运行大量单元测试。你怎么看待这种软件开发方法?
Donald:你听说的这个故事是一个典型的传说,它只有一个很小的“内核”是真的。事情的实际经过是这样的:John McCarthy于1971年决定举办一场“纪念日编程大赛(Memorial Day Programming Race)”。当时除我以外的所有参赛者都工作于斯坦福后山的AI实验室中。他们共同使用WAITS分时系统;我对校本部很不满,因为我当时能够使用的唯一的计算机是一台大型主机,我必须为卡打孔,然后提交给主机,它会以批处理的模式进行处理。我使用Wirth的ALGOLW系统(Pascal语言的前身)。我的程序第一次并不能工作,但幸运的是我可以使用Ed Satterthwaite的那个出色的ALGOLW离线调试系统,因此我只是运行了两次程序。另一方面,使用WAITS的家伙们一直没有得到足够的处理器周期,因为他们的机器负载太大了(我想,第二个完成的那个人,尽管使用了“现代的”方法,还是比使用老式方法却最终取胜的我晚了一个小时)。这并不是一场公平的竞赛。
谈到你刚才的问题,即时编译和“单元测试”的想法对我的吸引力非常有限,尤其在我身处完全未知的环境中时,这时我需要反馈,以确定什么可以工作,什么不可以。否则,我会在不需要做的事情和不必思考的问题上浪费很多时间。没有什么是需要“伪装(mock up)”的。
Andrew:对于开发者,尤其是客户端开发者,正在面临一个日渐明显的问题,即改变他们的思考方式,从线程的角度去编写程序。这个问题是由廉价的多核PC的出现导致的。它一定需要很多算法进行多线程化的改造,至少也需要做到线程安全的。到目前为止,从你已经发布的《计算加程序设计的艺术》(TAOCP)第4卷的大部分内容来看,还没有涉及到这方面内容。你接下来的工作会和并发与并行程序设计有关么?尤其是这个问题天生就与你现在研究的组合算法非常适合。
Donald:组合算法的研究领域非常庞杂,而我将有幸在三或四卷书中介绍它串行方面的内容,我认为串行方法的重要性不会降低。相反,并行技术的 “半衰期”其实非常短,因为硬件总在快速地变化,每一个新的机器都需要一些不同的方法。所以,很久以前我就决定在书中保留我最了解的内容。有很多人比我更了解并行机器,他们可以指导你如何面对同时性的问题;程序员应该听听他们的建议,而不是我的。
Andrew:很多多核处理器的供应商都在帮助开发者转移到多核模型的过程中,表现得力不从心。做为一名著名的教授,你对于这种转变有什么看法?什么因素才能促使这种转变?如果有更好的工具可以解决问题么,比如在语言中加入对并发更好的本地支持,或者使用框架?或者还有其他的方案么?
Donald:我不想回避你的问题。也许我个人的一些观点会为当前流行的多核架构趋势泼一盆冷水。在我看来,这种现象或多或少是由于硬件设计者已经无计可施了导致的,他们将Moore定律失效的责任推脱给软件开发者,而他们给我们的机器只是在某些指标上运行得更快了而已。如果多线程的想法被证明是失败的,我一点都不会感到惊讶,也许这比当年的Itanium还要糟糕——人们基本上无法开发出它所需要的编译器。
这么说吧:在过去的50年间,我编写过一千多个程序,其中有很多规模都很可观。但是如果说哪些程序的性能可以在并行或多核环境下有明显的改进,我恐怕连五个都说不来。比如,多核处理器对TeX肯定没有什么帮助。
你听说过有多少程序员对这种未来一片光明的机器抱有强烈的兴趣?我几乎没有听说过,除了他们的诉苦。尽管我们学院那些搞硬件的家伙一直想让我相信我是错的。
我知道有很多重要的应用依赖于并行——图形渲染、密码破解、图像扫描、物理与生物过程模拟等等。但是这些应用需要非常专业的代码以及特定用途的技术,而这些技术无疑每隔若干年都要变化。即使我对那些方法非常了解,可以把它们写入TAOCP中,这对于我的时间也是巨大的浪费,因为过不了多久,这部分内容就没有什么价值值得别人去读它了。(类似地,当我在准备第3卷的第三版时,也打算删除掉关于如何在磁带上排序的内容。这些内容曾经是软件领域里最热门的主题,现在再把它印在书中就是巨大的浪费了。)
我今天所用的机器有两个处理器。而我只有在同时运行两个独立的作业时,才会用到这两个处理器;这样很好,不过每周这种情况只会发生几分钟而已。如果我有四个、八个甚至更多的处理器,我同样得不到任何好处,想一想我是做什么的——我几乎每天每时每刻都在使用计算机。所以,我为什么要为硬件供应商承诺的未来而高兴?他们认为多核的到来可以为我的工作提速,我认为这是“白日梦”(pipe dream)。(不——这个比喻不准确!我是会用“Pipeline”的,但是不会用线程。也许我应该说这是个“泡影(bubble)”)
不过,我认为Web浏览器可能会由于多核的出现而有所改变。我是从技术性的工作,而不是消遣的角度在说。我也承认我还没有什么很好的想法,到底硬件设计者应该给我们除多核以外什么样的产品,不过他们现在在串行计算上的确遇到了麻烦。(但是我的MMIX设计中包含了很多考量,可以有效地提高我最关注的一些程序当前的性能——代价是与遗留的x86程序无法兼容。)
Andrew:软件开发领域中有一个很少被提及的问题:面对全新领域的软件,如何进行设计?当你着手开发TeX时,应该遇到过这样的问题:没有现成的源代码可以参考,而且在这个领域中你也不是专家。你是如何完成设计的?在你顺利地进入编码阶段以前,设计工作花了多少时间?
Donald:这又是一个好问题!我在《Literate Programming》一书的第10章、以及《Digital
Typography》一书的第1章和第2章中已经详尽的探讨了问题的答案。我相信任何对这个问题真正感兴趣的人都将乐于阅读这些章节。(还可以参考《Digital Typography》的第24和25两章,它包含了我在1977年做的TeX初始设计的第一版和第二版草稿。)
Andrew:关于TeX的书和程序自身都清楚地表现了对有限内存使用的考量——这是那个年代系统的一个重要问题。今天,对内存使用的关注则更多地与缓存大小有关了。每当有人设计出了新的处理器,你一定会关注“可感知缓存”和“缓存透明”的算法的问题。在你最近的工作里,你会谈论,或者只是间接地介绍一下,处理器缓存在算法设计中所扮演的角色么?
Donald:在前面我提到过,MMIX提供了实验的平台,可以在上面尝试多种不同的缓存。它是由软件来实现的机器,因此我们可以执行一些实验,它们从今天起在100年内都是可重复的。可以肯定的是,在新一版的TAOCP 1-3卷中,将会讨论在不同的缓存参数下,基本算法的不同行为。目前在第4卷中,我大约收集了十多个缓存内存和缓存友好的方法(更不用说“memo cache”了,这是一个与软件相关但又不同的概念)。
Andrew:你在编著TAOCP时都用到哪些工具了?你使用TeX?LaTeX?CWEB?Word?你在编程的时候使用哪些工具?
Donald:我通常的工作方式是用铅笔和纸先把所有东西都写下来,然后在旁边放一个大废纸篓。然后我使用Emacs将所有文本键入到机器中,当时要使用TeX风格。我使用TeX、dvips和gv查看结果,它们几乎可以瞬时显示出来。我使用Mathematica检查数学运算的结果。
我使用CWEB编写每一个经过讨论的算法(这样我才能充分地理解它),CWEB和GDB调试器简直是天作之合。我使用MetaPost制作插图(或者,在极少数的情况下,会在Mac上使用 Adobe Photoshop或Illustrator)。我有一些自己创作的工具,比如我自己的TeX拼写检查器和内置在Emacs 的CWEB。我自己设计了在 Emacs中使用的位图字体。我还有一些特殊的Emacs模式(mode),可以帮助我对文件中的好几万份论文和笔记进行分类;特定的Emacs快捷键使得写书的过程有点儿像演奏风琴。我喜欢用rxvt作为终端输出的窗口。从去年12月开始,我使用了一个名为backupfs的文件备份系统。我每天都需要对每一个文件进行归档,backupfs非常适合我的需要。
根据我机器上当前的目录来看,今年我已经写了68个不同的CWEB程序。其他的,2007年有100个左右,2006年90个,2007年100个,2004年90个。而且CWEB有一个非常方便的“改变文件”机制,这样我可以快速地为一个主题创建多个版本和修改了;在2008年,我目前为止已经在这68个主题上创建了73个修改。(有几个修改非常短,仅有几个字节;其他则达到了5KB甚至更多。有些CWEB程序非常重要,比如我完成于一月前的BDD包,它有55页。)因此,你可以看出文法式程序设计对于我有多么重要。
我现在正在一+_+立的Laptop上(没有网络连接)使用Ubuntu Linux。我偶尔会使用闪存驱动在Ubuntu Linux和Macs之间搬运数据。我用后者接入网络和处理图像;但是我相信我的“传家宝”只有Linux而已。顺便提一句,相对于GNOME和KDE环境,我更习惯把注意力留在键盘上,这样我可以能够使用经典的FVWM。不过似乎有很多人更喜欢GNOME和KDE。每个人都有不同的爱好。
Andrew:在你的站点上,你提到在Peoples Archive上最近制作了一系列视频,在其中你回顾了过去的生活。在第93段“给年轻人的建议”中,你提醒人们不应该只是简单地因为某件事时髦就去做它。有一点我们都心知肚明,软件开发比起其他学科,在产生时髦技术上有过之而无不及。你能举出两个当前正在流行的技术么?对于这些技术,也许开发者不应该简单地因为它们当前很流行,或者他们正在使用,就欣然接受它们。你是否愿意再举几个软件开发范围以外的例子呢?
Donald:这个问题非常矛盾。我通常都是建议年轻人要相信自己的判断,而不是其他人。我就是“其他人”中的一员。大概每一位你要效仿的“伟大人物”的传记上都会记载,他或她曾经向当时的 “传统智慧”发起过挑战。虽然如此,我并不想回避这个问题,尽管我也不想触动其他人敏感的神经——有一种软件方法学已经类似于某种宗教了。首先声明:没有任何人有任何理应该听信我这种计算机科学家/数学家对于软件开发的种种评论。我要说的是,几乎每一件我听说过的与术语“极限编程”相关的事情,看起来都绝对是错误的...除了一点例外。这个例外就是“团队工作”和“互相阅读源代码”的思想。这个想法非常关键,甚至可以弥补极限编程中其他匪夷所思的方面。那些令我很不安。
我还必须承认我对“可重用代码”的流行保有强烈的偏见。对我来说,“可重编辑的代码”要远远胜于一个无法触及的黑盒或工具集。就这个问题我还可以不断地说下去。如果你对可重用代码深信不疑,我可能丝毫无法动摇你,但是你也无法让我相信,可重用代码并不总是麻烦制造者。
还有一个问题你可能会问到:为什么新书的名为“第4卷 分册0”,而不是“第4卷
分册1”?答案是:计算机程序员将会明白——我还没有准备好从真正的起点开始写TAOCP的第4卷,因为我们知道不能贸然决定程序的初始设定,除非程序已经自身已经基本成形。因此在2005年,我开始编写第4卷的分册2,而在此之前已经有了分册3和4(想想星球大战,它是从第4部开始的)。
最后,我做好心理准备,可以编写前面的部分了,但是不久我又意识到简介部分就需要包含很多内容,它更适合成为一个独立的分册。因此,还记得Dijkstra的名言么,计数应该从0开始,于是就有了第4卷的分册0。今年晚些时候第4卷的分册1可以和大家见面。
(责任编辑:A6)