Archive for 2009年7月

C++:进程开销和内部复杂度

2009/07/27

C++ 为什么会被设计成现在这个样子,我一直认为和 Bjarne Stroustrup 的个人背景有很大关系。按照 Stroustrup 自己在 《The Design and Evolution of C++》里的描述,设计 C++ 的动机来自于他完成博士论文的时候编写一个模拟器缺乏合适的工具。从这段描述里,我冒昧地认为 Stroustrup 暴露了他早期的局限性,他意识到必须有更好的工具来管理系统的复杂性,但是眼光仅仅局限在源代码的层次。他的模拟器是一个单独的 monolith,在寻求更好设计时,Stroustrup 仅仅追求如何更好的管理这个 monolith 的内部结构,未曾考虑任何更高一级的方法——比如把 monolith 分割成相互协作的更小的模块——来提高系统的可维护性。

C++ 与进程开销

C++ 在 UNIX 上受到的欢迎程度最低,正是因为 UNIX  提供了更多的组织系统的方法,这些方法能够,而且经常是更好的代替源代码级别的方式。UNIX 不仅提供了进程和 IPC,让这些方式成为可能,而且还从一开始就不断寻求降低这些方法的开销,让它们相对于源码级的管理方式——也就是语言——更加有竞争力。所以,在 UNIX 上 C++ 没有获得它在其它一些操作系统中获得的那种主导地位。

在《The Art of UNIX Programming》的3.1.3节说的很清楚,“如果操作系统让创建进程的操作过于昂贵,或者让进程控制的操作过于困难或者过于死板,⋯⋯就会鼓励 (在一个较大的 monolithic 模块内部使用) 像 C++ 一类的源代码级别的内部分层结构,而不是 C 这样的 (在相互协作的小模块中) 相对平坦的内部结构。

我常说一句不太准确的玩笑话—— “C++ 就是微软捧起来的” 。其实也不是全无道理。作为在 PC 发展的黄金时代最广泛应用的操作系统,Windows 没有提供太多的系统级机制来管理应用软件的复杂度,开发者只能着眼于源代码级别的内部结构,寻求 C++ 之类的语言帮助。

C++ 的兴起和 PC 上 anti-UNIX 风格暂时的主导地位有很大关系。Stroustrup 的发明是对 UNIX 上管理系统复杂度的方式的一种不高明的重复。这种重复为那些由于历史原因或者因为经济原因 (比如过弱的硬件支持和操作系统支持) 没有普及 UNIX 文化的领域提供了一种似是而非的,拥有短期效益的替代品,因而受到了欢迎。

C++ 与内部复杂度

UNIX 文化鼓励通过进程和进程协作来降低单独模块的内部复杂度,而不赞成用 C++ 的方式来 “管理” 内部复杂度。事实上,UNIX 文化认为 C++ 的方式在鼓励过度的内部设计而不是有效的对其进行整体管理。

另一方面,C++ 不光忽略了在单个 monolith 的层次之上的管理方式,还低估了现有手段在单个 monolith 中应对复杂度的能力。做出这种错误判断的不只 Stroustrup 一人,在 90 年代操作系统领域兴盛一时的对 micro-kernel 的研究中,研究者和很多业界开发者都认为操作系统内核的复杂度已经到了必需舍弃 monolithic 式的内核设计,由 micro-kernel 加 user-space 进程实现的服务来替代。Linux kernel 的出现及时证明,用 C 这样的技术也足以很好的管理单个 monolithic kernel 的复杂度。Linux kernel 不光和很多 monolithic 内核同样稳定,还在性能和设计复杂度上拥有天然的优势。(比如,对于 Minix 的单线程文件系统的抱怨,其设计者反驳说该 feature 很好实现——但是始终没有真正实现,而对于 monolithic 内核来说,多线程文件系统几乎是自然而然的设计。)

今天,如果你把系统中某个组件的复杂度设计的比 Linux kernel 还高,那是一种罪过而不能被认为是必需使用 C++ 的理由。

结论

C++ 的兴起,在我看来很大程度上是不是一段普通的历史,而是反映了整个业界的一个错误。正如《The Art of UNIX Programming》所说,上世纪80年代,由于各个 UNIX 厂商的愚蠢,UNIX 文化曾经一度奄奄一息。而 UNIX 社区的开发者们又一再忽略兴起的 PC 市场 (而忘记了 UNIX 自己就是在 mainframe 的厂商忽视了 mini-computer 的情形下发展起来的)。在整个世界缺乏 UNIX 文化的情形下,出现了 C++ 这样畸形的尝试。

我承认世界并非完美。有些错误已经成为文化的一部分被保留下来。但是 UNIX 文化因为它强大的生命力终于逐渐回归。这显示出 C++ 不属于那类可以出于历史和文化原因而被永远保留的错误。这个错误至少应该不被扩大,并且可以被逐渐纠正。

Xcode并行编译

2009/07/26

Xcode 缺省使用系统所有的 CPU 来编译,也就是说,会最多同时启用和系统中 CPU core 数量相同的进程来编译。如果希望限制 Xcode 使用的并发进程数,可以如下修改配置:

defaults write com.apple.Xcode PBXNumberOfParallelBuildSubtasks 4

看来 Xcode 使用的最大进程数是安装的时候由 installer 计算的。

恐惧的守护

2009/07/24

《守护者》(Watchmen)的结局说明唯一能够真正守护人类的东西是恐惧,说好听一点叫做敬畏。这个恐惧不能太逼近太猛烈,否则一部分,甚至可能是大部分人会像《世界之战》(War of the Worlds)或者《终结者》里的败类一样自相残杀。这个恐惧也不能太远太模糊,否则就会像全球变暖成为 “狼来了” 的故事。

所以人类需要神时不时敲打一下,但是随后又被允许舒舒服服的喘息和反思。那么多超级英雄不能解决的问题,只要让其中的一个英雄成为全人类 “共同的敌人” ,人类自己就可以应付了。

初读《美铁之战》

2009/07/19

几个月前从《科幻世界》上读到《美铁之战》的第一部《云武士》。初时非常入迷,因为背景设定是我最喜欢的核战后,残留的人类群体的设定和描写也非常丰富。不过听说作者由于懒惰不断构思至今还没写完结局就中断了阅读,因为我不喜欢不完美的东西。后来想想又恢复了阅读,一来是因为主题实在是我非常喜欢的,二来因为这样也就不会在读到结局的时候感觉主人公们都离我们而去了——据说人脑幼稚地进化还没能让我们在心理深处区分实际的朋友和文学作品中虚构的人物。好吧,其实一个也很重要的原因是同事买了前四部而且我可以强借借阅。

刚刚读完第一部,发觉这部书里的美铁联邦作为一个集权社会有很多(和其它科幻作品中的设定相比)独特的地方。先记录下现在的想法。也许以后的阅读中还会有新的感受。

第一是联邦还允许人们建立亲属关系,尽管完全破坏了传统意义上的血亲,但是联邦手则建立的亲属关系从其它角度说很类似真正的亲情。而且也给某些违反手则的行为留下了非正式的存在空间。这可能是第一家族有意为之,为了给人们的压力留下最后的 “泄压阀” 。

第二是这个集权社会并没有实现完全的监控。这可能是多个原因的共同作用,第一是上面的 “泄压阀” 的考虑;第二是联邦可能确实没有资源实行全面的监控。和很多其它描写集权的科幻作品不同,联邦并不是一个控制全球的政权(如同《我们》中的大一统帝国,和《1984》里的大洋国——虽然未控制全球但是已经和其它国家订立了不打破僵局的默契),它受到外界——比如说平原变种人的威胁,所以联邦的资源并不能无所顾忌的投入到对内监控。

第三是联邦有意缩短了人民的寿命。这可是釜底抽薪的一招。相比之下,其它作品的集权社会竭尽全力的监控体系都忽视了最简单的一点而事倍功半,人要觉醒是需要成长的。《1984》的温斯顿·史密斯和《我们》的Д—503大约都是年过30的人才刚刚蒙蒙胧胧的反叛。联邦的寻道民到这个年龄不死也已经垂垂老矣。没有其它作品中的集权社会那种压抑,寻道民可以在青年时发挥更大的活力,同时在壮年死去让成熟之后的觉醒成为不可能。相比之下,大洋国那种让孩子来监视老人(以寻道民的标准)的做法可算是即浪费了青春,又把社会资源浪费在不安全的老人身上。(当然大洋国没有美铁联邦那种外部压力使得这种双重浪费并不太荒谬。)

看来美铁联邦的第一家族是目前我在科幻作品里面见到的对人性研究最透彻的,也是让一个集权社会能以最高效运行的最聪明的统治团体,不怪乎能建立集权统治达600年。美铁联邦的人民大多数也都没有大洋国和大一统国的人民活得那样压抑,他们过着追求荣誉的欢快生活,体验着战斗和男女之乐,免去了无谓的长寿带来的奇思怪想,还为美铁的终极目的贡献了一份力量。也不失为一种美好的生活方式。

核爆

2009/07/16

一直想做一个可以用在插图里的核爆。今天在星巴客等人的时候无聊就做完了。用的网上一张假想的“轰8”轰炸效果图修改的。

本来是想请雨鸿的设计师朋友做,告诉人家是“素描”效果。拿到“素描”效果之后发觉其实不是自己想要的。也不知道如何描述,只好自己来,结果还算满意。不过还是要谢谢雨鸿和她的朋友,有些灵感也是从这张素描效果上得来的。

进化与资源

2009/07/15

周末和老婆逛街,看到路边站着几个认识的发型师,是以前常常光顾的。后来他们离开了原来的理发店另外开了一家,就再没去关照生意,所以不好意思的低头走过。然后对老婆说:“刚才过去的那几个人是原来⋯⋯理发店的。” 老婆问:“怎么不在那里干了?” 我随口说:“店面缩水了,觉得没啥前途呗。” 老婆突然开始深沉:“我觉得人在这一点上和植物类似,总是需要发展空间。似乎其它动物并没有这个需求。”

这句话细想来突然感觉大有道理。植物需要发展空间的时候,正是自身需要的资源不断增长的时候。动物看起来不需要什么成长空间,似乎是因为动物对资源的需求不像植物那样虽着时间急剧增长。一颗树从小苗长大,需要的空间和日光照射面积会上百倍增长。一个人从婴儿长到成年,饭量会增大多少?我猜也就五六倍吧。

不过再考虑一下,其实动物的这个特点也仅仅是进化到哺乳动物这样的高级形态才开始的。爬行类之前都是一些终生不断变大的傻家伙,比如恐龙。似乎自然选择也在告诉物种,无限制的贪婪并不是求生之道。需要的资源越多,就越难容忍资源链的微小变化。

由于更精巧的身体结构,高等动物对资源的利用更加高效。复杂的系统不是高效率利用资源的充分条件,不过想要更高效率的利用资源,系统就必需更复杂。有效率的复杂人们称之为精巧。鸟类的翅膀比飞机的固定翼更能节省能量。微电脑控制的可变气门电喷发动机也比简单的化油器发动机更节油。回到人的发展空间这个话题,虽然人的身体进化到了生物链的顶端,但是在社会性发展发展方面似乎还停留在植物的进化水平。似乎老子和达摩这样的智者在试图探索如何进化到追求内心安宁的形态。但是大多数人还在考虑如何控制更多的资源,影响更多的其他人。虽然成人的饭量没有增长多少,可是对权力和影响力的追求比恐龙的生长速度还要快千万倍吧。

毕竟自然选择不是真正有什么东西在选择,也并非由善到恶的转变。文明中个体的进化也许本来就和自然中的不同。文明的整体就在不断拓展疆界,和食物采集的生活形态已经有了天壤之别。不过抱着对资源需求的克制态度追求更高度的自身内在精巧仍然是更好的发展方式吧。

C++与垃圾回收

2009/07/11

垃圾回收不是自动变速

最近几天遇到的好几个和内存回收有关的 C++ 程序的 bug 。有对同一个指针两次调用 delete ;还有在 delete 了一个对象之后又通过其它地方保存的指针调用了这个对象的方法。当然从开始学 C++ 就明白要绝对避免这些问题,但是如果两段没有配合好的代码在 call stack 里相隔几十个函数调用的时候,避免并不像一开始想想的那么容易。

造成内存回收问题的根源在于程序的复杂度增长带来了程序运行时的不确定性,程序员无法准确判断一个对象真正不再被使用的时机。最著名的不确定性的来源当属多线程。但是单线程的程序也会有及高的不确定性。今天在 Mac OS X 或者 Windows 之类的操作系统上编写一个拥有 UI 的应用程序,可以很少或者根本不使用多线程——程序的大多数动作都可以在消息处理线程内完成。这样的单线程机制可以让 UI Framework 的设计和使用简单一些,能在大多数情况下避免线程同步操作的使用。但是当程序越来越复杂时,即使不引入多线程,单一的消息处理线程本身具有的不确定度绝对不比多线程低。

一些比较费时的函数有时会在整个函数的运行过程中的某些步骤把控制权暂时交还给系统的消息处理框架。如果在某个消息处理函数中调用了这样的函数,就会导致在这个消息处理函数会被不能确定的其它消息处理函数打断。有时候一个顺序过程的几个步骤会在多个消息处理函数调用中分别完成,触发这些消息处理函数的消息可能由一个函数统一排入消息队列,也有可能是由完成上一个步骤的消息处理函数把触发下一个步骤的消息排入队列。而且,看似单独的用户操作往往会触发几个甚至十几个消息。比如,最简单的鼠标双击在很多系统中都会触发一个鼠标单击和一个鼠标双击事件。考虑到前面提到的情况,处理这两个事件的消息处理函数可能是顺序运行的,也可能是后一个函数间插在第一个函数的运行过程中;而这两个消息处理函数本身还有可能向消息队列排入自己创建的消息,导致更大的不确定性。可以说,今天的消息处理线程本身已经和一个小型操作系统的进程调度模块的复杂度不相上下。本身是单线程,却已经有了多线程的逻辑。

从架构设计的角度看,我们应该尽量通过合理的设计来减少这样的不确定性。但是,从实际看来,很难把这种不确定性降低到能够准确判断一个对象可以在哪行代码的位置被回收的程度。而且,如今的程序要集成不同的 API。这些 API 和消息处理线程集成的方式往往有很大差别,这些差别的细微之处很少被文档完全提及,即使文档完全描述了这些细节,程序员也无法从中分析出两个或者多个不同的 API 集成在一起会发生的所有情况。

每个关于资源回收的 bug 都要根据具体出错的情况,找出原先对回收对象的位置的错误判断,然后找出更合理的回收时机。虽然最后这些 bug 的病症都通过修改回收对象的时机解除了,仍然难以确保没有隐藏的问题。回头看看,在一个拥有垃圾回收的系统中,这些 bug 都不会存在——没有必要耗费精力分析一个对象到底何时可以被安全的回收,当没有人使用它的时候它就会回收。我们关心的其实不是这个对象到底什么时候应该被回收,我们只关心它最终会被回收。一个缺乏垃圾回收的系统让我们不得不玩一场不停回答“什么时候应该被回收”的问题的游戏。

想到这里,我记起当一个激烈批评 Java 的人被问到 Java 是否一无是处的时候,他说 Java 无可争议的积极的历史功绩是把垃圾回收这个概念带回了主流的开发领域。尽管 Java 的垃圾回收最初实现的很不理想,尽管 Java 正在被其它拥有垃圾回收功能语言替代,但是由于它出现的合适时机以及 Sun 在其中所施展的市场手段让它拥有这个荣誉。

如果说推广垃圾回收概念是 Java 的历史功绩。那么没能实现垃圾回收可以说是 C++ 的历史罪责。在提高处理软件复杂度的能力的尝试中,C++ 是认知度最高的,也是在资源消耗上最为节俭的一种尝试。所以 C++ 成了一个标杆——人们开始认为 C++ 有的特性都是大型软件开发必需的,C++ 没有的特性都是大型软件开发可选的——前者就像汽车中的变速箱,是必需的;后者就像自动变速箱,高手是可以不用的。垃圾回收是 C++ 始终不曾具备的特性,但是我开始认为它不是自动变速箱,它是每个大型软件的开发都不可缺少的。抛弃垃圾回收的人认为只是把驾驶的汽车从自动变速换成了手动变速,其实是把一个好的变速箱换成了一个漏油的变速箱。

错失的机会和无用的补救

从 C++ 所处时代的外部环境来说,它有机会引入垃圾回收吗?常常有人用 C++ 出现时的硬件条件来为 C++ 缺少垃圾回收进行辩护。同时代的 Smalltalk 推广的失败,和早期Java 垃圾回收器的糟糕表现为这个说法增加了旁证。

但是,Smalltalk 和 Java 的垃圾回收只是一个特例。像 Eiffel 语言的垃圾回收器的效率证明了垃圾回收完全可以实现的很高效。更重要的是,C++ 没有必要非得实现像 Java 那样基于 root-reach 的使用单独线程的垃圾回收,在硬件条件比较差的时代,一个基于引用计数的垃圾回收器的效率是完全可以接受的。所以,在早期阶段失去引入垃圾回收的机会很难说是一种由于历史原因造成的无奈和必需的牺牲,更像是一个由于短视和偏见造成的错误判断。

C++ 的辩护者的另一个理论是 C++ 是有垃圾回收器的。C++ 既有基于 root-reach 的垃圾回收方案,也有著名的 shared_ptr 来充当基于引用计数的垃圾回收。我认为,这两个机制本身的设计是成功的。(我曾经遇到过一些 bug 用普通的分析很难确定对象应该何时被销毁,其中一些 bug 涉及的指针范围很小,所以我把相关的裸指针全部替换为 shared_ptr 很容易就解决了问题。)但是它们作用在实际中大大降低了,原因在于它们是基于库而不是基于语言的机制。

垃圾回收的内存管理方式需要整个系统的所有模块共同遵守。只要有一个模块放弃了垃圾回收,其它模块的垃圾回收也就名存实亡了。这个原则对于基于引用计数的垃圾回收更为重要。因为基于引用计数的垃圾回收明显在 C++ 使用者中认同率更高,所以这个原则对于 C++ 的垃圾回收也更为重要。由于没有语言强制,当程序复杂度增高,集成的第三方代码来源复杂之后,如果垃圾回收只是一个库而不是一个语言的强制特性的话,系统的开发者和维护者会越来越无力保证所有模块都采用垃圾回收,也没办法避免不同的模块采用实现细节千差万别的垃圾回收。这样整个系统的垃圾回收根本无法作为一个降低复杂度的工具,它本身就成了更大的复杂度的根源。(像上文括号中提到的那类 bug,你并不是总能把所有的裸指针很容易的替换成 shared_ptr。不说有时候你不能获得源代码,就算在获得所有源码的情况下,修改低层库的一个指针的存储方式带来的代码修改量也是不可接受的。)

在这里我们可以把 C++ 的 shared_ptr 和 Objective C 1.0 的引用计数方案做一个比较。从某种意义上说,C++ 的 shared_ptr 更有优势,因为它利用程序的 block scope 来自动实现引用计数的增减,而 Objective C 需要程序员自己通过 retain 和 release 消息来维护引用计数。但是由于 C++ 不强制使用 shared_ptr,从 shared_ptr 中也可以取出裸指针,在复杂程序中只要少部分模块直接使用裸指针或者 delete 操作,就会让 shared_ptr 带来的益处大大降低甚至消失。Objective C 1.0 的方案虽然不能自动增减引用计数,但是由于它是强制性的,保证了它能够真正的降低整个系统的复杂度。

而且,随着硬件水平的提高,基于引用计数的垃圾回收逐渐被淘汰,被基于 root-reach 的垃圾回收取代。C++ 采用裸指针以及把 C++ 对象混同于普通的 C struct 来存储是引入 root-reach 垃圾回收的一大难以克服的障碍。Objective C 也兼容 C,但是它把自己的对象和 C 的元素相对独立开来,让 Objective C 2.0 可以没有太大困难的引入 root-reach 垃圾回收。

结论

一个技术的前景,还要看它的现状。被采用的越多的技术,就越能吸引越多的开发者。技术的推广超过某个临界点就会开始不可逆转的向整个业界渗透的趋势。

在采用垃圾回收的过程中,Mac OS X 走在了前列,它自带的主要应用,以及苹果开发的其它主要软件都是使用具有垃圾回收的 Objective C (包括 1.0 的引用计数)。在 Mac OS X 上用 Python 和 Ruby 等语言写的软件也不少。所以开发 Mac OS X 应用使用垃圾回收已经成为主流。QT、GTK 和 Carbon 反而已经成为边缘。Linux 有许许多多用 Python、Ruby 编写的采用垃圾回收的应用。像 Emacs 这样的风格更是一个传奇——自己独立实现一个带有垃圾回收的解释器。不过用 C++ 编写程序仍然在 Linux 上和拥有垃圾回收的语言分庭抗礼。而Windows是一个荒谬的现象。微软早就在叫嚷 C++ 的消亡。除了企业开发和一些小工具,Windows 上却一个采用垃圾回收的大型应用都不存在。

缺乏垃圾回收决定了 C++ 不是一种适宜大规模软件开发的语言。C++ 的目标——能够比 C 语言能更容易的应对复杂度更高的软件——可以说很大程度上没有达到。漏油的变速箱时常贴贴补补,加加变速油还是可以硬撑的,但是使用它绝对不是一个愉快的体验。另一方面,凭借多年的积累,C++ 在很多平台上拥有基本相似而且开放的实现——这方面其它语言不是支持的平台比较少,就是开放程度不高,所以在某些领域 C++ 的这些资本还可以暂时抵消它的缺点,C++ 还可以用 QT、GTK 这样的形式得到应用。但是我认为 C++ 这些资本的价值也会随着 Python、Objective C 这类语言对更多平台支持的增加(同时,随着那些拒不对垃圾回收提供更好支持和推广的平台的消亡)而逐渐消失。希望软件的内存管理全面的转向垃圾回收。垃圾回收不再是某种语言的特性,而是像函数、文件这样的概念,成为软件开发一个基本的不可缺少的概念。

柯达彩色胶卷的停产

2009/07/04

得知柯达停产传统彩色胶卷有段时间了——记不得当时在什么媒体上看到的。前天才有机会详读了一篇相关评论。看过之后,还真是感受良多。

这篇评论给我的感觉是流露出一丝惋惜的情绪。传统彩色胶卷是没有今天的数码摄影技术那么方便,不过一些了解它的人感觉,传统胶卷除了至今仍然略微胜出的(但是已经被数码技术的拥护者们认为无关痛痒)的色彩饱和度之外,还在技术上拥有一份数码技术没有的雅致。

简单转述一下从这篇评论里了解到的知识。在柯达胶卷之前的彩色摄影使用的底片其实本质上仍然是黑白底片——也就是只能感受光的整体强度(intensity)而对光的频率没有反映感光材料。这些早期彩色摄影纪录色彩的方式是把被摄光线用棱镜或者其它光学方法分解为三到四组单色光,让每种色光分别在底片上感光。而还原影像是用对应的单色光照射显影后的底片,再把结果合成。柯达底片的奇妙在于,它在薄薄的一层底片上,分布了三种可以直接感受不同色光的感光材料。也就是说,薄薄的一层柯达胶卷,就完成了早期技术分光和感光两个步骤。而且,经过进一步改良的柯达胶卷,还把感光材应的颜料也放置在胶卷上,对应不同的暴光度,在显影过程中相应的颜料就会在胶卷上呈现不同的色彩透明度。这相当于把早期技术的分光、感光、影像还原中的单色打光技术同时集成在一张薄薄的胶卷上。

把传统彩色胶卷推下历史舞台的数码摄影技术,其实还是回到了原来先光学分光,再分别单色暴光(用只能感受光强的材料),然后再合成的技术。只不过这次由于电子设备的介入,感光材料和合成显影的过程大大简化,才让分光暴光技术有资本替代了传统胶卷。回过头看传统彩卷,虽然还需要不太方便的显影过程,但是整个胶卷显然是一个比电子元件更精密更紧凑的分子级机器。

技术发展常常有两条路。一条是不断摸索自然界能够给我们提供的天然资源或者通过化学等手段从自然界得到的合成材料,另一条是善于对已经掌握的资源进行简单组合。人类科技的加速发展有很大成分是因为后一种“简单组合”起了更大的作用。像原始人和古人不断发现各种能够作为颜料的物质,今天的人们只要发现能够适合LCD的三原色的物质或者适合打印纸的CMYK四种物质,就能组合出无数的颜色。早期的汽车工业不断摸索如何制造出性能优良的让驾驶员能够随时掌控汽车姿态底盘,今天廉价汽车已经不再花费过多的精力设计底盘,而是用分别控制四轮刹车的ESP等电子系统来防止车辆失控。瑞士的工匠不断的考虑如何把齿轮进行巧妙的组合,而同样的功能用几条指令和一个芯片就能廉价的获得。

善用大自然的赠与是技术的最高效率。就像传统的柯达胶卷和传统的颜料,不需要整个电子行业的支撑,不需要复杂的墨点控制,一样能够得到精彩的效果。假设有一场灾难摧毁了我们的实体科技,但是保留了知识,那么首先被恢复的技术应该是柯达胶卷这样的技术,因为分子级机器在精巧紧凑的同时,还无虚一个庞大的支撑工业。不过,发现这种赠与是困难的。把某些已经掌握的知识做得小巧精致,然后加以组合,看起来是一种短时间内前景广阔的道路,计算机和电子技术发展之后人类已经越来越在这条路上驾轻就熟。不过这些组合和自然的机器相比,有那么一点儿笨拙。像传统彩卷一样,很多传统技术的精巧性都体现在原子级别的。电子技术和计算机技术从唯美的角度看来相对笨拙。不过可惜按照目前这种方式发现原子级别的可利用技术几率太低了——相对于按照摩尔定律缩小晶体管和编制软件的花费。

也许当纳米技术和其它操纵微观事物的技术成熟之后,这两条技术之路会会合成一条大道。就如同试验化学家们多年以来期待让化学也能成为一门通过计算和演绎得出成果的学科。像科幻小说《天渊》里的描写——在爬行界的人类文明千年梦寐以求的反重力技术,在蜘蛛人的星球上以反重力物质的形式被发现。看过《深渊上的火》的人都知道,那些反重力物质一定是飞跃界技术的遗留的纳米级机器。也许有一天分子级或者亚原子级的机器不是再像柯达胶卷那样通过试验被“发现”,而是像编写软件一样被随心所欲的设计出来。那时我们今天的以晶体管为单位的组合技术就会实际显得笨拙可笑(而不是仅仅在我的瞎想中)。胶卷也会以某种形式重生。

空心魔方

2009/07/02

昨天逛超市发现了这个空心魔方。挺有意思。因为不知道中心的颜色,所以用传统的方法复原有一点困难,会因为出错不得不回搠。可能得死记一下中心颜色的相对位置——我现在只记得红对黄,其它的都是靠瞎蒙,最糟糕的时候复原一次要重试三次。