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

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

超乎预期的《变形金刚2》

2009/06/30

似乎应了那句老话——期望越高,失望越大。《星际迷航》、《终结者4》、《变形金刚2》这三部片子即将上映的时候,我最不看好的就是《变形金刚2》。不过统统看过之后,失望最小的是《变形金刚2》——甚至应该说还有一些惊喜。

其实我对《变形金刚》电影的不满在于它对原始形象的肆意修改。和《终结者4》对T-800始终如一的展现相比,《变形金刚》对威震天的形象设定简直只能用“What the fuck”来形容。

走进影院终于发现习惯了朋克风格和反乌托邦风格之后,对《星际迷航》这类太过歌剧风格的电影已经略感厌倦(《Lost in Space》的票房惨淡似乎也是因为歌剧风格过于浓重)。而且这部最新的《星际迷航》情节明显有些单薄。比如科克和史巴克的指挥权争夺形同儿戏。为什么地球和史巴克母星全文明的力量都拿那艘采矿船改装的星球毁灭者无能为力而企业号一己之力就将其击溃?《终结者4》最大的败笔则是最后马库思在状态良好的情况下牺牲自己拯救约翰。虽然高尚,不过牺牲一个活蹦乱跳的人来搭救另一个人无论如何不是让所有人都能从伦理上接受的决定。

相比之下《变形金刚2》的情节比较流畅。没有什么磕磕绊绊的地方和让人反感的地方。其中出现的变成美女的变形金刚还在提醒大家,我们变形金刚比什么终结者T-800T-1000T-X都牛多了。看我们的形象多么完美。比起你们那种刚刚脱离人类怀抱的人工智能要强大万倍。

其实撇开对威震天形象的不满,我很喜欢《变形金刚》的一些设定。非碳基自主生命体是《变形金刚》提出的独特概念(而且是在80年代初)。变形金刚不是机器,比如,他们有自己无法解释也无法创造的灵魂,他们的身体构成既不同于普通的机器也不同于碳基生命(广义的碳基生命,比如在高温下硅和碳的常温性质相仿,所以这种类型的高温硅基生命形态也可以看成碳基生命,或者称为有机生命)。

对《变形金刚》的喜爱有很大一部分来自其小说。这部小说的设定是第一部真人电影的前传。小说着力描写了电影不曾似乎也无力表达的一些迷人的问题。比如,变形金刚是永生的,他们对待战争和生命短暂的智慧生物的看法会和我们有什么不同?再有,变形金刚对人类的技术奇异点视若无物。他们有自主的思维,但是同时检索和精确分析的能力又超群,红蜘蛛在小说中用几十秒就能理解人类超级计算机的所有程序并控制其运行。这样的生物,他们延续和发展文明的手段与我们有什么不同(比如,人类不可能靠少数个体延续文明,必须依靠强大的行星工业体系)?另外,他们也有自己的技术奇异点,火种是他们一直不懈研究但是又无法解答的问题。是否所有文明最终都有无法超越的奇异点?

威震天和红蜘蛛又一次在结尾逃走了。不过相比其它的系列电影没完没了的开放结局,《变形金刚》似乎更有资格这样做。金刚们有的是时间,几百万年一瞬而过。

Mac OS X的字体[2]

2009/06/27

《Mac OS X的字体》发布之后,甫鸼提出了一系列质疑。当然他没有否认很多人认为《Vista puts Mac OS X font rendering to shame》的作者是微软的枪手(不过修辞十分诡异),但是回避了自己对该文的看法。

我对Mac OS X的字体确实有所偏爱,周围的很多人此的看法与我不同。其实当下有多少人与我感觉异同的重要性在其次,我更希望搞明白的是人们做出偏爱Windows的判断有多少成分是出于习惯,有多少是出于(潜意识中的)深层次原因。但是这个问题并不那么好回答。

Vista puts Mac OS X font rendering to shame》(并非原文,而是附带的评论和调查)的意义在于给这个问题添加了一个可信度很高的旁证(尽管由此得出确定性的结论还显轻率)——62%的参与投票的人更欣赏Mac OS X的字体渲染效果,也许可以一定程度上说明身边人的不同看法在于这些人群接触Mac的比例还是不如北美高;及评论中给出的各方面解释,很大程度上说明从深层次原因看还是Mac OS X的方式更有优势;综合说来,很多偏爱Windows的判断中武断的习惯的成分更高一些。搞清楚这个一方面满足了我的好奇心,一方面也是对未来的一种预测——基于习惯的选择往往会逐渐让位给基于其它本质原因的选择。(当然有些习惯的力量是巨大到无法改变的,比如键盘的QWERT排列。不过Mac OS X已经取得的9%的份额让我相信关于字体渲染的习惯没有巨大到无法改变。)

下面讨论一下甫鸼的疑问。第一是显示器分辨率的提高能否“自动”减轻Mac OS X字体边缘发虚的问题。首先说明,这里的分辨率不是像素数,而是每英寸像素数。所以iPhone的屏幕虽小,分辨率却高于大多数LCD的分辨率。在解释“能”与“不能”之前,重申一点,边缘发虚是一个缺点,但是在无法达到完美的计算机方案中称其为代价更加合适,而《Mac OS X的字体》已经解释了这种代价是合理并且值得的。也就是说,即使这个问题还停留在今天的程度,对于字体渲染的整体优劣也并无影响。

下面说说这个问题能否被“自动”减轻,首先举两个例子,第一是《Vista puts Mac OS X font rendering to shame》的评论2.2.1.1.4,在评论者的旧CRT显示器坏掉之后,他为自己的旧Mac接上了新的LCD,同样的硬件(除了显示器),同样的渲染算法(苹果从Mac OS 9就采用的),在接上新LCD之后字体的效果焕然一新;第二是很多人使用了iPhone之后,都感觉iPhone的显示效果比LCD要好;而且当整个大页面缩小到小于iPhone屏幕的时候,虽然不适合阅读,但是页面的布局和整体效果是不错的,而且很多情况下单个字体仍然可以分辨,而基于Windows CE的设备在相同的比例下字体已经完全不可辨认。

例子就是例子,我不想用两个例子就粗暴的泛化到一般情况,但是实例也有其独特的说服力。另外从推理的角度看,重视准确度的渲染方案和一般图形的渲染方案相比原则上更为一致。一般图形的反走样算法也是重视准确度的。也就是说,在Mac OS X上对一条普通贝塞尔曲线的反走样(anti-alias)算法基本上与Mac OS X上一个字型上的贝塞尔曲线的渲染方法是一致的。而Windows上对字型的处理是区别于一般图形的,你不可能把Windows对字型的那种强行修改以适应显示器像素的做法应用到普通的斜线或是曲线的反走样上,所以Windows的字型渲染在Windows的整体图形方案中是ad-hoc的(从《Mac OS X的字体》的截图中,IE对于日文字体中的斜线的处理可以看出,如果真的把Windows的字型渲染方式应用到斜线上是多么恐怖——因为日文假名中存在比较明显的斜线,而拉丁字母中比较少见长斜线,所以这一现象对于英语使用者并不熟悉)。

总的说来,实例说明Mac OS X的方式不经太多调整就能很好的适应显示器分辨率的提高。而推理说明,即使Mac OS X的字体渲染真的需要调整,只要借鉴普通图形方案的调整经验就好。另外,苹果始终坚持同时控制软硬件最后把关的做法也能占到先机,可以比较严格的控制Mac OS X运行的硬件平台,从而选择适合Mac OS X的显示器材。

对于字体选择的问题,很高兴Windows缺省自带的文本编辑器采用了两级管理的方式。不过Word 2007和很多其它更专业的应用似乎没有这样做:

基本上似乎是因为Windows APIs主要还是用font face来列出字体。文本编辑器自己做了归类管理。但是很多功能更全的应用似乎把精力花在了别处。高兴的是,Office 2008 for Mac的字体管理是两级的。另外在《Mac OS X的字体》中有一点没有提到,Mac OS X的字体既可以在系统级别安装,也可以为用户单独安装,这一点似乎也是Windows没有的。(由此也一窥Mac OS X的Unix血统让其多用户风格自然呈现,而Windows的单用户风格难以在短期内消除。)

接着是Safari在Windows上的字体问题。严格的说,这个不算是字体渲染的问题,因为很明显是字体的选择出现了问题。(OK,我承认我也引入了字体管理这个和渲染不相关的问题。)这个问题我得研究一下,因为手头没有在用Windows,而且还要下载Safari for Windows。不过,Mac OS X本身的字体渲染体验仍然是完美的。而且字体选择的问题终究没有字体渲染的问题那么难以修改。 🙂

最后是关于苹果软件的字体渲染功能的提供问题。上面说的字体渲染策略都是指Windows平台上和在Mac OS X上由操作系统提供的方案,准确的说在Windows平台上是GDI,在Mac OS X上是Quartz。当然一个在Windows平台上的应用选择不使用GDI的字体渲染方案也可以,那就是用GDI的低级原语(如像素)来自行渲染,Adobe Acrobat for Windows和Safari for Windows基本上就是这样做的典型例子。不用Quartz提供的字型渲染也可以,但是似乎没有Mac OS X的应用这么做。FireFox、Opera在每个平台上都是直接使用平台本身的渲染的,Microsoft Office也是如此。所以看看他们的渲染效果更有代表性。