BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Ralph Johnson、Joe Armstrong:并行编程未来一席谈
录制于:

| 受访者 Ralph Johnson 关注 1 他的粉丝 , Joe Armstrong 关注 2 他的粉丝 作者 Werner Schuster 关注 4 他的粉丝 发布于 2010年9月6日 | QCon北京2018全面起航:开启与Netflix、微软、ThoughtWorks等公司的技术创新之路!
39:10

个人简介 Ralph Johnson是《设计模式》一书作者四人组中的一员,并且创建了最早的重构浏览器,他现在就职于UIUC公司的CS部门,担任UIUC模式/软件架构小组的主管。
Joe Armstrong是Erlang语言的主要发明者。他一直在Ericsson工作,在此他开发了Erlang,并担任Erlang/OTP系统的首席架构师。

QCon是由C4Media媒体集团InfoQ网站主办的全球顶级技术盛会,每年在伦敦、旧金山、东京、北京召开。2009年4月,QCon首次登陆北京。QCon Beijing 2010大会吸引了700多名架构师、项目经理、资深开发者和技术领导者、以及200多家企业的参与,并获得了业界空前的好评!

   

1. 首先我要请教Ralph Johnson一个问题。你正在着手创建并行编程模式,并且已经有了一定的进展。可否请你对该项工作做下说明?

Ralph Johnson:我们的成员一部分来自于加州大学伯克利分校和伊利诺大学,还有一部分来自于Intel、微软以及一些国家实验室。我们这些人一起合作,制定基本的并行计算模式文档,而这些模式大多数都来自于高性能计算领域。之前你曾经问过我是否要写一本书,显然我们最终的目标是要不依赖这些书,但那并不是当前的目标。我们当前的目标是要描述出它到底是什么。 我们正在为模式制定文档,但是看下我们的软件,看能否说“在我们的实际软件项目中应用这些模式”,或者“我们获得所有模式了吗?遗漏什么了吗?”并非所有人都是学院派,但是我们会对此持学术的观点。我们期望可以编写出一本大家可以遵照执行的书。实际上,我们的小组中有不少项目就是这么做的,但那并非我们这个小组真正的目的所在,也不是我个人的目标。

   

2. 这些模式处于什么级别?

Ralph Johnson:这些模式所处的级别多种多样。最重要的是,因为有了多核进而拥有大量并行计算机,我们才要创建这些模式。我们已经做了一些准备工作,但在将来还要做更多的工作,因为人们不知道如何对其进行处理。我们应该怎样描述并行计算中的工作原理,并让人们理解它呢?我会考虑如何讲授这些知识。我们专注于提高程序的性能,这是通过使用多个处理器,并且对程序进行切分达到的。

   

3. 并行编程中的算法。

Ralph Johnson:并行计算中的模式与面向对象的模式之间的区别之一在于,在并行编程中你会经常改变算法。这会对你使用的算法产生影响。在面向对象的编程过程中则不存在这种问题。有些模式实际上是关于算法本身的,而有些模式更关注于系统的总体架构,因为会有一些确定的方式来将程序组合到一起,那会使其成为特定类型的并行机制。

例如,如果你使用管道(pipe)和过滤器(filter)的方法,这种方法通常是为了重用代码,而不是为了进行并行处理,但是如果你有一台并行计算机,那么显然管道的不同阶段会运行在不同的处理器上,这样你就一定会在某种程度上得到性能的提升。然而,另一方面,如果在架构的中心区域有一台大型的数据库,所有程序都会访问它,那么在那里就很可能会存在瓶颈,你需要做些工作,以防止这种情况的发生。

你获得这种架构,就获得了想要使用的算法,然后就可以开始使用真正的并行机制了。那些东西并非全部与并行相关,它们更多的是关于并行阶段的设定。然后我们会获得这样的模式,它们会关注于并行机制是否最终会分发,或者你是否将其放在特定的像管道之类的几何区域(geometric regions)中,你拥有树结构,就有了多种不同的进行并行处理的方式,并且你会寻找方法来对其进行组织。

   

4. 并行编程中的数据结构。

Ralph Johnson:我们需要采用特定的数据结构,也就是来用来保持数据同步的技术。消息传递(message passing)是其中之一,而共享内存显得更加重要,因为人们正在使用这种技术。Joe将会告诉我们,为什么共享内存的方式不具有可伸缩性,我也同意他的观点,但那不在本次话题的讨论范围之内。人们当前就是那么做的。它会一直深入到更底层中。很重要的是,我们使用了不同的编程规范或者编程风格。我想这比所谓的模式更加复杂,但是我们也把它叫做“模式”。

有一种组织并行编程的知识的方式,但很遗憾只是一部分,而让我们不快的是有大量不同的选择。幸运的是,没有哪个项目能够选择所有方式。我们只会选择其中的一部分,这样就会保留很多机会。在将来我们可能会发现,某种方式比另一种更有效,然后我们就会对其进行筛选,而不是把所有都保留下来。但通常情况下,还有很多方式会被继续使用。

   

5. GPU的角色

Ralph Johnson:我们讨论的是多核,但是对于面向GPU编程的人们来说这意味着什么呢?那是更高级别上的并行。它的风格不同,架构的类型也不同。也许我们会发现有些情况使用多核处理并不是非常有效,而在GPU中就会有效地工作。当然,我们现在还只有四核的处理器,也许不久你就会用到八核的处理器。

当我们拥有上百个处理器的时候,它们之间就会有更多的消息传递。我认为到那个时候,共享内存的方式将不再有效,尽管暂时还不会发生。如果你专注的是人们当前是怎么做的,哪种方式是有效的,那就是我们所关注的模式。

   

6. 这个问题让我们来请教Joe Armstrong。对于此您的观点如何?

Joe Armstrong:这很难说。我已经试过从不同的角度来处理并行机制,但最开始都是要让系统具有容错性。我一直认为,想要让系统具备容错性,你必须有两台计算机。显然,使用一台你是无法达到完全的容错性的。如果它崩溃了,就不会再继续工作,所以你需要两台计算机,并使它们并行而且是分布式的。如果你想要让系统具有容错性,很自然地就会涉及到分布式计算,还肯定会涉及到并行计算。

   

7. 使用Erlang对现实世界建模。

Joe Armstrong:我对并行机制的架构方面更感兴趣,特别是能够反映真实世界的内容。我认为有一些程序员觉得编写并行程序很困难,而还有一部分人(Erlang人群)觉得很容易。我已经做了25年,我只想说“没有那么难,真的很简单。”实际上世界是并行的,而不是线性的,我们在现实世界中处理同时发生的事情毫无问题。比方说,有五个人坐在这间屋子里,两位在摄像机前,而另外三位坐在摄像机后。

我们都会同时做多件事情,并且通过传递消息来进行沟通,我们很容易理解这样的说法。当我们将各个组件粘合在一起的时候,就会在组件之间传递消息,对于这样的观点我们也很容易理解,如果我在英国编写了一个程序,另一个人在澳大利亚编写了一个程序,我想要使用它的程序所提供的服务,那么我别无选择,只能向它发送消息,然后等待返回的响应。

我们使用消息作为组件之间的媒介将它们粘合在一起。不幸的是,对于同一台机器上的组件和分布式系统中的组件,我们无法使用同一种方法来粘合。你可能会面临很不合理的情况,人们可能会使用一种语言,像Java,来编写一个程序,并运行在JVM中;然后他们又编写了.NET的程序,那么将这些程序粘合在一起就比较困难了。这完全是不合理的!我们应该可以将这些程序都粘合在一起。当你在Internet的环境中时,程序都是通过使用socket来粘合的,这样,很不幸的是,每个人都需要为将程序粘合在一起而定义自己的协议。

   

8. IPC的协议处于何种状态?

Joe Armstrong:如果你查看一下TCP中指定的协议数量(我刚刚检查过,因为我明天还有个演讲),我想其中大概有4800个协议。其中的一个协议是针对示例HTTP(example HTTP)的,它的文档有120页,它会告诉你这个协议到底是什么。所有这些英文文档都使用了特别的描述方式,这让我们很难将它们组合在一起。但是那也要比粘合同一台计算机上的系统要容易。这种情况很不合理,我们能够将Internet上的系统粘合在一起,却无法将小环境中的系统粘合在一起。

我所感兴趣的是你如何将一切粘合在一起,以及怎么做到的。通过增加需要粘合的组件的数量你可以获得性能,只有组件都是独立的时候,你才会得到性能上的提升。如果不是独立的,那么你就得不到性能的提升。如果你只有一个入口点,那么这个点上的性能就会决定整体上的性能。共享内存在本质上是邪恶的,因为它破坏了容错性,它会生成单独的入口点,在那里如果发生故障,就会对性能产生很大的限制。

如果我们也有共享的记忆,那么就会很困难,因为我们的大脑会被粘合在一起,出门去任何地方都要一起行动。我可不喜欢那样。我们有不同的世界观,可以通过发送消息来更新它。我关于并行算法的想法是将问题分解,让它只是在组件之间来回传递消息,并且我认为是我们开拓了这种全新的编程方式。

   

9. 语言支持能够如何对代理编程(agent programming)起到帮助。

Joe Armstrong:我们(的思想)来自于代理编程,并且Erlang已经成为这种编程方式的先驱语言。现在我们要让这种方式也深入到其它语言中。不要认为这会非常困难。如果你没有正确的抽象,那当然会使这件事情变得非常困难。例如,如果我要讲数学课,但是我只知道罗马数字,你会想到,乘法会非常难。但是如果考虑使用阿拉伯数字,那就会变得简单得多。因为如果我们使用罗马数字,就没有办法来表示0。

这只是我的一种假设,否则整个数学学科就不仅仅是困难的问题了,而是根本就不可能存在了。如果我们进行了错误的抽象,那么就会使很简单的事情变得很困难。我认为那正是在并行编程领域所发生的。我们使用了错误的抽象,这使得事情变得非常困难。

这就是为什么我们试图引入模式的原因,它会解决这个问题。如果我们进行了错误的抽象,那么怎么可能使用这种方式呢?它会让我们根本无法工作!如果你改变看世界的方式,那么它就会变得更简单一些。

   

10. Erlang中的并行模式。

Ralph Johnson:我们的目录中的有些模式(特别的数据结构等等)可能会像这样,对于并行模式来说,算法的策略和二分法类似,你将一个问题分为两部分,然后再将每个部分再分别分解为两个部分,最终你会得到完整的任务树。当你计算叶子节点的值的时候,你会将它们重新组合到一起,那就是很不错的方式,可以很快地处理并行或者并发的问题。

我们也可以在Erlang中这样做。有些模式可以在任何类型的问题上广泛应用,但还有一些只能应用于特定的情况。就像我所说的,当你做与模式相关的工作时,就像是考古学家在找那里有什么东西,而不是试图发明什么东西。通常我们都会提交一些论文,它们都非常酷,但那是发明,还不是模式。如果那是个好主意,很多人都会复制那样的做法,那么它就变成了模式,模式的重点就在于要看到人们做的是什么以及为什么要那样做。

有时,之所以要这么做,是因为你不知道有更好的方法,其实通常会有另外真正的理由。随着技术的改变,理由也会发生变化,那样曾经是那样做很好的理由就变得不再是好的理由了。但是通常还会有好的理由,让人们去做各种事情。我们真的是在试图研究人们在做什么。在Erlang中有很多模式,因此他们会拥有自己的一套模式。

   

11. 在Erlang中有并行模式吗?

Joe Armstrong:这么说很有趣,因为我没有看到什么模式。也可以说我曾经看到了一两个模式。例如,我们在做分布式的编程。调用存储过程的时候你会发送消息,然后等着返回响应,然后知道有些东西崩溃了,以及它为什么会崩溃,错误是什么样的——那就是模式。我觉得很难想象拥有一大堆的模式。我确实也看到过非常复杂的行为,它们都可以放在某种框架中处理。

故障恢复就是这样的例子。如果你拥有这种模式的话,情况就会是这样的:其中一台计算机在做某项工作,突然发生了故障,那么正在使用的客户端就应该可以转向到另一台计算机,工作会继续进行,就像什么都没有发生过一样。我将此视为一种高级的模式。你其实不需要很多模式来构建系统。最好的做法是拥有几个模式作为组件,你可以用很有趣的方式将它们组合在一起。如果你拥有太多模式,就会搞混的。

   

12. 在OTP中就是那样吗?并且你在那里就是这么做的吗?

Joe Armstrong:没错,我们拥有六七个模式,然后把它们应用在各种情况下,看起来已经足够了。

Ralph Johnson:大多数都是关于容错的模式吧。

Joe Armstrong:其中之一是关于容错的。它只是创建一棵树,然后如果有组件出了问题,那么就会报告给树状结构,然后父节点就会试图修正子节点中的错误。我们有一台客户端服务器(client server),一个事件日志记录器,我们也有一些非常复杂的模式,事实上除了创建者之外没有人用它,那都是系统升级的结果。我们可以发布系统,然后向前或者向后滚动版本。如果出错,就会回滚。这确实有点儿难于理解。

这些都是Erlang中的模式,但是都很少使用。你会针对整个系统拥有一个系统升级模式,因为你只拥有一套系统。客户端服务器会大量应用它,那是主要的模式。然后,你可能还会创建一些有趣的模式,让客户端服务器接受其他人的响应。我向你提出问题,但是从别人那里得到答案,我也认为已经得到了响应。那是很有用的一种方式,因为它让我们可以委托事件。

我不知道你们是否会把下面的内容叫做模式,它主要会被集成到协议和我们响应的消息中。所有一切都需要对消息的编码变更做出响应。如果消息的编码发生了改变,我们有了新的编码,那么你就应该改变所有与这个消息编码改变相关的内容。这种情况很常见。那就是我用来升级系统的方式。我们可以试想一下这样的系统(我明天会对其加以讨论),其中你只是在每个节点上放置空的服务器,而且你可能在世界上的每个Internet节点上都放置空服务器。

它们根本不做任何事,然后你向它们发送消息,你会变成一台HTTP服务器吗?你能变成一台FTP服务器吗?你能变成一台IRC服务器或者类似的服务器吗?一会儿之后,一个团队可能会说“你的编码有错误,你应该问,你能变成一台新的FTP服务器吗?一台新的HTTP服务器吗?”在某种意义上,如果你开始时拥有的是一台固定的服务器,像Apache,那么你就可以在其中放置模块来改变它的行为,但是在那之前你会后退一个等级。

开始时你可能拥有的是一台不做任何事情的服务器,它只是让你可以在其中放置代码的框架,然后你在其中部署一些程序,并把它转换成为Apache服务器。然后你可以在其中放置程序,并指定它的行为。一般我们会认为,如果系统的基础级别非常通用而不是专用的,并且我们通过网络来传送代码,那么它们就会成为你期望的样子。它们这样工作了一段时间之后,然后你会告诉它们去做一些其它的事情。

我看不出问题出在什么地方,为什么这会很困难呢?这就像它拥有你的老板,而你拥有你的员工和人,并且他们知道如何做事,并且说“好的,现在你可以给墙刷油漆了。当你完成之后,就可以铺地毯或者做其它的什么事儿了。”这是我们编写程序的方式,我们说“现在你做一会儿HTTP服务器,直到我们完成,然后你再变成一台存储服务器”。这并不困难。

有种叫做框架库的东西(我不确定如何叫它)变得越来越流行了。Intel将这种东西叫做线程化的构建模块(threaded building blocks),微软在Visual Studio中增加了TPL和PPL。一种针对C++,而另一种针对C#,我记不清那种是那种了。在Java中则有并发库(concurrency library)。

   

13. 轻量级的任务 vs I/O

Ralph Johnson:以上的各种框架库非常类似,它们都是基于轻量级任务的,但是让人不快的是,在其中没有任何I/O处理。当你使用它们,并且用来描述并行算法的时候,如果你尝试进行任何I/O处理,那么最终就会导致你的线程被堵塞,它们都只是轻量级的任务,那意味着唯一的线程会在不同的任务之间来回切换。因此,为了得到好的性能,你会希望该线程专注于运行你的任务,而不是阻塞你的任务。

在某种意义上,这些都是反I/O的,如果你试图在其中进行I/O操作,就会导致很差的性能。人们正在寻找让你可以在其中进行I/O操作的方法,但是基本上这会达到不同的目的。它的目的只是以并行的方式运行你的算法。当你确实需要进行I/O操作时,问题在于你应该如何将数据结构化。另外,人们还倾向于创建消息传递模型。

我想这是因为人们拥有大量的C或者Java的代码文件,它们都会共享内存,并且他们想要重用这些代码,并且想要在其中引入并行性。这些库都很流行,因为你可以把它们添加到那些框架库中,并且为框架库引入并行机制,这样导致的问题会比正常情况下少得多。

   

14. 共享内存所存在的问题。

Ralph Johnson:毫无疑问,共享内存和并行性给我们带来了很多问题,的确是那样。在伊利诺斯大学我们使用这样的说法——“疯狂的共享内存”。疯狂的共享内存意味着只是使用信息和线程,并试图让它们同步。这在某种程度上是操作系统开发人员的传统做法,在某些地方应用很广泛,但是我觉得Erlang中的虚拟机只在很少的几个地方采用了这种方式。

当你在Erlang中编程的时候,永远都不需要为此而担心。在伊利诺斯大学有很多不同的项目,人们对于如何解决问题也持有多种不同的观点。有些人倾向于使用消息传递,而另一些人想要使用类型系统(type system)来证实彼此之间没有干扰,从而你可以编写多个共享内存的过程,而不需要显式地进行数据同步,因为编译器会确保那都是自动发生的。

这其中包括的内容范围很广泛,但一般来说,人们都认为使用共享内存的显式同步这种旧方式很容易导致错误。这主要是由于它会导致冲突。比方说两个处理器,一个试图读取内存,而另一个试图在同时写入内存。你不知道事情是按照什么顺序发生的。这样,当你引入很多同步操作来解决问题的时候,就可能会造成死锁。那是多年以来一直存在的传统问题。我还记得Dijkstra曾经在1968年关于这个问题撰写过一篇论文。

那篇论文实际上是关于操作系统的,它给出了操作系统的总体结构,实际上40多年来我们一直沿用这种结构,那篇论文附有两页的附录,其中说到“我项目组中的一位同事有个很酷的主意,让我来向你说明一下吧。”然后他就说明了这个问题。

我认为这非常棒,那篇论文最后的内容非常吸引人,它在构建操作系统的过程中非常重要,但这是一种大师才可以使用的方法。它并非是你想要放在通常的应用程序中的东西。我认为人们已经从中学到了很多,并且整个社区基本上都认同这种观点。

   

15. 共享内存 VS 程序的正确性

Joe Armstrong:我同意,尽管我认为这不在你建议的范围之内,因为关于共享内存的问题没有死锁之类的问题那么严重。它是错误代码造成的。如果你拥有两个程序,它们彼此之间共享内存,而我将程序送交给你的程序,但是它出错了。就会破坏内存,计算结果也是错的。它会在内存中放置错误的值,而不会发出通知,其它的组件和其它程序都不知道内存已经被破坏,从而必然会导致错误。

将组件粘合在一起要注意的最基本问题就是,我的程序不能和你的程序混在一起。这是最基本的要求。我曾经写过文章来证明这个观点的正确性,并且坚信它是正确的,如果你编写过程序,那么也会相信这是正确的。我们将二者都放在同一台计算机中,那么其中的一个就会破坏另一个,然后我们会忘掉所有关于程序和质量控制以及其他的一切原则。唯一的实现方式就是要确保它们都是分离的。在共享内存情况下,即便拥有错误恢复我们也不能把两个程序放在一起。绝对没有任何方式能够让它们有效工作。

我认为应该在编程中做出的另一种改变是,要先创建组件,然后再把这些创建好的组件粘合在一起。将组件组合在一起的唯一方式就是通过传递消息来完成,你也可以使用共享内存,但是我并不认为那是一种粘合组件的好方法。

现在我们讨论的是非常敏感的问题,因为在基础级别上,我们实际上无法与编程语言中的数据类型保持一致。C语言中有integer类型,Erlang中也有integer类型,但是Erlang中的integer可以表示百万以上的数字,而C中表示的是32位或者64位长的数字,我们需要对此时刻保持警惕。

   

16. 通信协议中XML和s-exprs的角色

Joe Armstrong:如果我们无法对什么是integer达成一致,那么在谈及整型数的时候就要非常注意,否则就会导致很严重的问题。当我们使用闭包以及高顺位的函数的时候,我们到底应该如何传递这些参数呢?我们无法从Erlang向Fortran传递函数,因为Fortran根本不知道什么是函数。

虽然我们应该可以使用某种透明的消息传递方式,但是我们不得不使用类似于XML的东西,那非常痛苦,因为它们都冗长无比。另外,它无法解决最基本的保持数据类型一致的问题。我们没有发现有哪种编程语言能够自己对协议进行描述。我们需要一种独立的新语言来描述协议。

Ralph Johnson:人们在过去曾经描述过这种语言,但是问题在于你需要与其保持完全的一致。我们想要通过制定多种标准来解决这种异质性的问题,但我们不能先是与其完全符合,然后又制定另外一种标准,让所有人再去符合这种标准,就像20年前CORBA一样,它就是想要成为这样的一种标准。

Joe Armstrong:如果我们让组件使用s-expressions来通过socket进行通信,那么我们早就可以忽略类型转换的问题,也不用使用4800个协议,一个就足够了。这是应该在多年前就完成的工作。那也是XML变得如此流行的原因所在。

Ralph Johnson: XML与s-expressions有什么区别吗?

Joe Armstrong: XML不使用圆括号,而是使用有趣而且奇怪的括号。但是关于嵌套方式我认为没什么区别。如果你的记性很差,那么可以将标签先放在下面。如果记性很好,你就可以依次匹配那些括号。XML已经有了属于自己的语法,也就是DTD或者类似的东西,它会描述数据结构是什么类型的,不使用它的人很不幸。如果你的XML是一种带有特定语法的数据结构类型,你会把它通过网络发送,那就是很好的开始。

我们没有定义协议,因为我们不知道它们应该按照什么顺序执行。人们一般制定的协议就是包的结构,他们会说“如果我把那个包发送给你,那么你要把那个发回给我”。但是不会说“如果我把A发送给你,那么在传递给我C之前不能给我传递B”,那样的语言不存在,但却应该存在。

Ralph Johnson:那肯定是不准确的,人们已经编写了那样的语言。我认为这是因为我们这个行业还没有认真对待消息传递的问题,因此也没有人认为我们需要标准化。这是研究人员已经做过的事情。

   

17. API协议。

Joe Armstrong:我认为可以把它浓缩到API中,比方说你查看一个文件系统,就可以打开文件、关闭文件以及对文件进行读写。我还从没看到过这样的文档,其中说明的是:如果你打开文件,然后将其关闭,那么你就再无法读取它了。这并没有在API中进行说明。你在程序中会控制文件,并且可以对其进行读取。文档之所以没有说你不允许读取已关闭的文件,是因为每个人都知道,那就没问题。

每个人都知道就没问题,但是规则的验证程序不知道这一点,而且数学方法也不知道如何处理,你需要告诉它们。你可以在状态机中添加这样的信息,说“当文件处于打开的状态时,你就可以对其进行读取”,或者“当你关闭了文件,就会将状态变为‘关闭’,当文件处于‘关闭’状态的时候,你就无法读取它。”

但是API不会告诉我们这些事情,它只会告诉我们不想知道的内容,而关于它所允许执行操作的顺序等重要的内容,它根本就不告诉我们。那被叫做协议,而我们非常不擅长描述协议。实际上,工程师会使用包嗅探器(packet sniffer)来查看发生了什么,不过那可不是什么好方法。

   

18. 有什么用来描述协议的方法吗?请举例。

Joe Armstrong:我认为Tony Hoare的通信序列过程(CSP)是描述协议的典范。当我最早创建Erlang的时候,就试图以某种方式实现CSP,但是它无法正常工作。Erlang在某种程度上是失败的,它应该使用Prolog来实现CSP,但是没能成功,最终只是以自己的方式实现。也许在这些方面我们可以退回去重新来过。

Ralph Johnson:我知道已经有一种研究中的系统——名称应该是Statemate——它已经为类型系统增加了状态,从而你可以了解到对象的状态会如何随着时间的推移而改变。这个项目属于IBM,它至少是在十年前开始的。这些观点一次又一次出现,但是在大学的研究实验室中的人们只会编写比玩具系统稍微好一点儿的系统,他们做了很多应用程序,但是即便所有人都不去了解,世界也会一切照旧。

一些年之后,有人又提出了同样的言论。很多非常棒的内容都被忽略了,而我们说的是,当你拥有好东西(我认为Erlang就是)的时候,它可以做一些其他系统完成不了的工作,而且持续了十多年,那么它就是非常可靠的,人们就很难抛弃它而不受任何影响。

如果你是微软,那么所要做的就是在大型会议上发布声明,然后每个人都会注意到,并且第二天你就可以让上万个程序员使用它。但如果你不是,那么就很难推广你的好主意了。这就是现实。

   

19. 研究成果和主流之间的30年鸿沟

Joe Armstrong:这看起来是计算机领域的悖论。你看到昨晚Dan Ingalls的演讲了吗?非常棒!因为他向我们展示了他在开发Smalltak的过程中,在最早的Smalltalk-76中开发的示例。他展示了一些小型的下拉菜单,我猜测他们在Xerox PARC发明了下拉菜单,并且找到了与传统操作系统交互的方式,你在菜单的各处都可以发现——你点击一些东西,然后就会看到下拉菜单。

他所展示的程序都可以在Smalltalk-76环境上执行,那是在上世纪70年代创建的,他不仅可以创建下拉菜单,因为他已经向我们展示了,还能够旋转菜单。整个下拉菜单会旋转一个角度,或者你可以让其自旋,或者在屏幕四处自旋,或者做类似的动作等等。而现在,我们无法在计算机上完成1978年所能够做到的事情,这太荒谬了!

到底发生了什么事呢?Xerox的人们创建了窗口系统,他们创建类似的菜单,然后这些主意的一部分转而成为计算机领域的主流,而其它的都滞后了。很荒谬的是,我们现在还没有让30年前开发的东西成为主流。这绝对是太奇怪了。对于Prolog来说也是同样。如果你不使用SQL,而使用Prolog的查询,那就太疯狂了。

谓词逻辑是一种极为强大的编程工具。我们都是程序员孤岛(islands of programmers),在开发者大会上,我们有很多开发.NET程序的队伍参加,还有其它使用JVM的队伍参加,但这两群人相互之间不交流,他们的应用程序也无法协同工作。我认为,我们都处于一个世界中,在那里我们想要把所有现存的程序都组合到一起,因为我们拥有上百万行代码,也不想在另一种框架中重新实现一遍。我们会利用已有的东西。

   

20. 服务的便利性

Joe Armstrong:我认为最大的突破在于存储方面。像Amazon S3之类的系统使得存储非常简单。你只需花费15美分就可以获得1G空间一个月的使用权。而对于你自己来说那是不可能的。慢慢地我们会习惯这些东西。我们个人会使用存储设备,但不会在企业系统中那么做,我们可以从别人那里购买。然后我们还会舍弃其他东西,比方说带有查询功能的数据库。我们会舍弃数据库,而将它们放在别的地方。想要达到这样的目的,我们必须使用通信协议,而且我们已经看到了这种趋势。

我并没有看到这样做会得到什么便利。之前我曾经与Ralph交谈过,我们想购买每月1G的存储空间,但是可靠性要很好,如果丢失了我们的数据就要赔偿一百万。我认为这样会很便利,你有了货运班轮就可以确保不会因为船沉了就丢失所有的货物,但是我们为什么不能保证我们公司数据的安全呢?因为那样的话我会把它存在其它的地方,而不会为此而花费一百万。

如果你查看真正的成本,你会想要自己来创建存储系统吗?你能够自己做——出去购买磁盘,那样1TB的容量会花费你100英镑。买一些磁盘,雇佣一名程序员,让它24消失不间断地运行,然后就要看你的运气如何了。

Ralph Johnson:磁盘是无关紧要的,重要的是备份、管理等等其他的一切。

Joe Armstrong:我们期待存储的便利性。我多年前就曾说过这些基础的问题,并且确定其中之一就是存储问题——你如何存储数据。接下来的任务是你如何查找数据,既然我们已经拥有大量的数据,那么到底怎么才能找到想要的呢。Google的解决方案是对一切都建立索引,如果你有足够大的存储空间,那就没有问题,另外还要有足够多的计算机。

我们能够找到想要的数据,并且也能够存储数据,那么接下来的问题就是我找到的很多东西都是垃圾,所以我需要对内容进行过滤。如果你查看一下从网络上获得的东西,就会发现我所言非虚。前几天我查看了房屋广告,因为我想买一间公寓。我点击了一项结果,并查看所有这些页面,然后我就考虑“我想知道在底层发生了什么”,所以我对所有内容进行了跟踪,结果发现了一个很小的代理服务器,并且捕获到它,在上面我找到了与我发送的房屋广告相关的137项URL请求和页面。

其中大多数页面都满是广告。他们甚至将图片设置为不可缓存(non-cacheable),从而迫使浏览器刷新页面,将广告放进去。我其实对此不感兴趣,我感兴趣的是公寓的价格、房间的数量、房间的大小以及它需要我付出的钱。我认为之前的网络中发送的是编写好的HTML代码,那是信息量非常大的内容。我认为噪音率的情况越来越差。它不就是垃圾邮件吗?房屋广告中拥有五倍的信息量,其中隐藏着多达几兆的内容,而我根本对它们不感兴趣。

那么,你如何看待这种聚集和混合呢?他们通过反向工程提取了信息内容。香农定律指出,信息的数量与数据的日志数量是成正比的。首要的问题是要让每个人都得到数据,现在的第二个问题是我们如何才能让每个人都得到数据。我们可以存储数据,并且可以在其中查找数据,但是现在我们需要对其进行过滤,从而得到有用的内容。

这就是各种带有便利性的分布式内容,对于这些内容,我并不认为实际上需要很多协议。我想说我们需要的是存储——存储API。除了获取和存放数据之外,对于存储你能做哪些更多的事情呢,可能就是要永远存储那些内容吧。

Ralph Johnson:每个人都说:“我们实际上不需要这么多。”但是在你知道所需要使用的东西之前,人们会一直发明越来越多的东西。

Joe Armstrong:那是因为他们的时间太多了。

Ralph Johnson:不,这是因为你所说的存储问题,但那也会出现在所有的医学信息系统中,其中保存着你的健康记录。

Joe Armstrong:但是你还是在获取和存放数据,没错吧。你看,获取Joe Armstrong的数据,存放Joe Armstrong的数据。然后你就会得到子密钥“存放他的体重或者头发的长度”。

Ralph Johnson:但是你开始拥有服务了,你开始要求它做更多的事情。

Joe Armstrong:是的,但是那不会和存储耦合在一起,除非你想要将服务放在存储之中。

Ralph Johnson:但是你说你所拥有的只有存储……

Joe Armstrong:不,我并没有说你所拥有的只有存储。我说的是,如果你拥有了存储,那么就可以使其更便利,只是把它放在那,并且拥有不错的协议,问题就解决了,但这会导致另一个问题,就是如何解析协议。

Ralph Johnson:我同意,让存储更便利非常重要。我所要说的是,你说你会为存储创建固定的协议,非常好!但是你说我们只会拥有固定数量的协议,那可不会是个小数目,它的数量会比存储还要多。

存储很重要,但是如果你考虑到我们还有HTTP,我们要通过HTTP来存放这些数据,那样人们就会在HTTP之上放置类似SOAP的层,或者你应该如何解析URL呢,对URL解码的方式也是一种协议,人们只是向其中添加越来越多的信息。那是因为他们做的也越来越多。人们总是会有特殊的需求。

   

21. 协议是世界上最通用的语言吗?

Ralph Johnson:我认为那就是为什么不要拥有固定的一组协议的重要性所在,我们要拥有协议定义语言(protocol definition languages),因为人们会不停地发明新的协议。

Joe Armstrong:也对也不对。可能世界上用的最多的编程语言(我猜)是postscript。每次你在现代的打印机上打印资料的时候,就会向它发送程序,那就是Postscript程序,然后你会执行它,这样打印好的资料就从打印机中出来了。

Postscript还从未做过任何的改变。你为每篇文档都发送了上兆的Postscript,而那完全是固定的。它已经多年没有改变过了。这为我们提供了极大的好处。

Ralph Johnson:但是程序员也不会使用Postscript来编写程序吧,程序员只是编写程序来生成Postscript。

Joe Armstrong:还是有一些人会那么做。

Ralph Johnson:你是因为那样而出名的,但你不是寻常人。一般的人可不会使用Postscript来编写程序。

Joe Armstrong:有位朋友就直接使用Postscript编写程序,他将文档发送给工作人员之后,他们就说“你能把源代码发送给我吗?”他就说“你已经得到了啊。”“我需要编辑所有的Postscript来修订你的文档吗?”“没错。”我想这有些极端,因为他是位控制狂人(control freak)。

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT