« July 2007 | Main | September 2007 »

August 30, 2007

make 使用笔记

我们的项目使用的构建工具,从今年初开始,从 boost jam 转移到 gnu make 。

makefile 写起来并不是一件轻松的事情,但是 make 的规则比 jam 要简单许多(比 boost jam 更简洁易懂),很符合 unix 的 KISS 美学。学会用 make 以后,编程方式可以得到极大的扩展,比用 IDE 的时代要灵活许多。尤其是可以用大量的使用自生成代码,或是用工具去生成数据文件,这些在 IDE 里做会相对麻烦。我们的开发,也不用局限在少数几种语言上了。

make 这个工具,我基本上是边学边用的,遇到什么问题临时想个方法弄一下。这最终导致 makefile 看起来很丑陋。但没有关系,写 makefile 跟写程序一样,以后可以不断重构。况且使用 makefile 本身,就很容易做任何自动化的工作了。

今天随便写几个最近遇到的问题,以及解决方案。

跨平台的问题

我们的项目是跨平台的,自然我希望一套代码可以在各种平台下都能通过编译。所以我希望 makefile 里可以识别出具体平台。

Windows 平台的识别比较简单,我们不打算支持 Windows 9x 下编译(但可以在 Win9x 运行)。Windows NT 下,似乎可以读到一个环境变量 OS = Windows_NT 。识别出这个就一定是 Win32 平台了。

Posix 兼容的系统中,大部分代码是可以直接编译的,少部分还需要区分一下具体平台版本。通常会有一个环境变量叫做 OSTYPE ,可惜这个变量里放的是 OS 的具体版本号,比如我的桌面系统就是 freebsd6.2 。Linux 系统下似乎也会带上版本号。

后来我们换了个方法,改调用 shell 指令 uname 来解决这个问题。在 makefile 里写上 OS=$(shell uname) 即可。Freebsd 下是 FreeBSD ,Linux 下统一是 Linux 。

用管道生成数据文件的问题

我们项目中几乎所有的数据文件,都要求在开发期使用人眼可读的文本。这个决定是前几个月才做的,但是这几个月的应用中已经几次获益。人眼可读的文本总是可以很快发现许多开发工具的 bug ,一旦生成的数据有文件,找出来非常容易。

但是由于种种原因(不一定是效率原因),最终我们用到的数据文件可能还需要多最初的文本做一些有限的格式转换。所以我们写了一些数据转换的工具。

不仅如此,我们还有一些源代码生成器,也是需要处理一些文本,生成一些目标数据的。

在我们的项目里便有了许多的文本处理工具,有些可以借用 unix 下的现成工具,有些需要自己写。自己写的那些,为了代码简洁,我们通常没有实现太多的命令行参数,而仅仅用标准输入输出来处理数据。最终看起来是这样的:

cat xxx.src | my_processor.exe > xxx.obj (windows 下则用 type 代替 cat)

my_processor.exe 是我们自己实现的文本处理器,有时候这个处理器没有被正常生成出来,或者本身处理出错,会导致不能正确的生成 xxx.obj 。

make 会因为程序运行出错而中断 make 流程,但是管道操作却有个特性:无论你程序是否正常退出,管道重定向的目标文件一定会被 shell 创建出来。也就是说, xxx.obj 一定会被创建出来,当出错时,它是一个长度为 0 的空文件。

这种情况下,第 2 次 make ,就会因为 xxx.obj 已经存在,而不会重新 build 它这个目标。

为了解决这个问题,我采用了这样一个做法:

cat xxx.src | my_processor.exe > xxx.obj.tmp && mv xxx.obj.tmp xxx.obj ( Windows 下用 type 代替 cat ,用 move /Y 代替 mv )

一旦中间出错,只会生成临时文件 xxx.obj.tmp 而不会产生 xxx.obj 了。


btw, 前几天鼓动同事在他的笔记本上装了 Ubuntu ,还是很不错的,他已经决定放弃 Windows 了。我不喜欢用本本,继续用 freebsd 做桌面好了。

微软应该不担心开源社区的人鼓捣 gcc kde gnome 这些东西,因为用 windows 的人永远会觉得 VC 更好用,Windows 桌面更强。Firefox 和 opera 能抢下 IE 的部分市场,也只是因为 IE 的安全性实在是值得担忧。真正对 windows 造成威胁的是越来越多的面对最终用户的应用程序可以在其他桌面系统上运行。比如我们正在开发的游戏。

我不反对 Windows ,但是我希望这个世界能有更多选择。

August 29, 2007

一些琐事

又是很久没写 blog 了。

小学的时候很讨厌写日记,但是父母老师要求写,我也就写了许多。结果现在翻出来读,倒是兴趣盎然,可以回忆去不少当年的心情。

高中开始到大学,我都坚持在写日记。有一年,一个漂亮女生送了一本日记本给我。突然觉得记录生活很有趣,当我把那一本日记写满后,也就没写了。后来似乎在电脑里写了一些,写完后加上了超长的密码,加密码的时候就打算忘记的,结果真的忘记了。文件在换机器时自然就删掉了。

blog 的原意就是写公开日记吧。但是我的生活在别人眼里看来很无趣,只有自己乐在其中,这种生活没啥记录的意义。比如过去的两周:

感觉自己最近两年体重下降的很厉害,通常这意味着身体不如以前。重新制订了健身计划,器械主要是腹肌板、哑铃、指力板。一周三次,安排在晚饭四个小时后,每次时间四十分钟。

周末觉得应该呼吸点新鲜空气,抄起一本很早读过一遍的书:黄仁宇的《中国大历史》,散步到水边坐了一下午。其间除了一个陌生人带着他的未上学的小女儿在同一条椅子上歇了下脚,再无人打搅。直到夜色降临,换到附近的咖啡馆把书读完。

桥牌很久没打,三缺一很长时间了。花了一晚上给新同事培训,然后今天打了一晚上牌。对于一个第一次打牌的新人来说,玩的已经很不错了。打桥牌可以体验到许多推理的乐趣。说起推理,刚把《死亡笔记》看完了。比我的期望值高。

travian 在新服务器上开了分村,打了几场漂亮的埋伏。

引擎的 client 移植到了 Linux (Ubuntu )上。以前一直可以在 freebsd 上跑的,本以为 freebsd 版本可以直接和 linux 兼容。实际操作的时候还是需要一些细微改动。最终为 posix / X 实现的版本可以两者兼顾了。

老妈来信告戒我要注意身体,信上写着晚上几点是身体哪个器官休息的时间。可我这几年几乎没在 12 点前入睡过,这么看,这几年受损伤最大的是肝脏了吧?但是这些到底是什么道理呢?其实我每天都有保证 10 小时睡眠的。再一次试着调整生物钟,有一天七点起来了,精神不错。可惜只坚持了一天……

最近最大的烦恼是:正在做的事情似乎工程庞大,以至于做任何其他的事情都要精打细算它们可能分走多少精力。

人的生命,因为其有限,所以精彩。

August 21, 2007

数学是一种思考方式

这几天有个读者来来去去给我写了几封 email ,问起我的观点:数学和编程是什么关系?学编程需要多深的数学基础?到底需要掌握哪些数学知识,对编程能力的提高有帮助。

这个还真不好说。

如果说起课堂上我们学到的知识。除了初等代数,在编程中我还真没碰到多少依赖数学技能来解决的问题。当年我学 C 语言的时候很小,甚至不知道数学中函数这个概念,还不一样把 C 语言学完了。虽然过了些年,我才把数学中的函数和程序中的函数联系起来。

做 3d 游戏编程,大学里的线性代数可能还用的到一点。至少得知道矩阵运算吧。但是大部分程序员并不需要接触这些东西。除此之外,如果说程序员必须精通微积分才能编程,那绝对是鬼扯。

如果对用编程的手段解决各种问题感兴趣,或许相关领域的数学知识有些用。比如我时常由于兴趣,做一些数据统计分析工作,这时概率统计的知识就少不了。但是解决问题,编程和数学一样,都只是工具。他们的地位是平等的,并非编程的技能依赖数学技能。

那么,学习数学有用吗?当然有必要。因为数学是一种思考方式,编程需要这样的思考方式。

我有个朋友,十年前认识他的时候,他说他在学佛。有一个问题没弄明白:佛说,不要执着。那么执着于不要执着是不是一种执着。

过了好些年,他还没弄明白这个问题。

学佛怎可以执着于这样的语言逻辑呢?光读佛经是没有用的,道理有时候需要顿悟。数学也如此。

学习数学绝对不是无休止的解题训练,我们需要悟到其中的思考方法。那种逻辑严密的推理,对完美境界的构建。发现理论上的缺陷,并对其分析,重新构作。当然,这个过程,又需要我们做大量的练习,借此领悟其中的道理。

编程也一样,不断的编写代码本身并不能直接提高编程能力。我们需要的是对问题的洞察力,构建系统的能力,理解机器运行时来龙去脉的能力,等等。而这些能力又是在不断编程实践中顿悟出来的。

编程和数学一样,是绝对严谨的。程序有特定的输入,经过特定的流程,一定有特定的输出。对于程序中的 bug ,我们不能抱有神秘论。它们不会没来由的出现,没来由的消逝。这就跟数学证明一样,逻辑或概念的缺陷不会随着时间消失,总等待后人来修补。

另一方面,在数学中,直觉也是很重要的。直觉可以帮助我们快速理解问题,解决问题。对数学了解的越多,数学的直觉就越准。很多数学知识,不需要太多研究学习,靠直觉就可以理解了。程序写多了的人通常也会有这种感觉 :D

只是有时候,数学中有些命题很直观,但是证明过程却非常繁杂。

比如拓扑学中的若当曲线定理:平面上一条简单闭曲线 C 恰好可以把平面分成两个区域,一个是内部,一个是外部。换句话说,平面上的点被分为了两类:在曲线外部的点集 A,和在曲线内部的点集 B 。在同一点集中的任意两点都可以用一条不与 C 相交的曲线相连,而连接一对不属于同一点集的两点的连线必然和 C 相交。

这个定理看起来很直观,显然是对的。但是一般人很难做出严格的数学证明,甚至很难看懂其证明。

现代编程我们经常会遇到类似的东西。尤其在现在系统越来越复杂的情况下,一段很简单的应用程序代码,你可以很显然的知道它能做什么,但是很少有人可以完全解释清楚它是怎样一步步做到的。比如一段很简单的 Windows 程序代码就是这样。只有拥有追根问底的数学精神,才会刨进操作系统底层,去搞明白系统到底怎样工作。这些不是一日之功,甚至不是三五年就够了的。而许多庸庸碌碌的程序员,满足于拖两个控件,粘合一下代码。最终只会感叹,程序只能写到三十岁。要我说,平庸资质如我,三十岁能入门就不错啦。

数学的发展历史中,又包含了许多人无穷的创造力。光靠逻辑推理来一步步解决问题显然是不够的。很多数学问题的解决,都起源于某种直觉,某种创造性构建,甚至把许多表面不相关的东西牵连在一起思考。然后再通过逻辑严密的推导过程来完善它。

例如,费马大定理的最终证明。首先找到了关于费马方程的解所在的费马曲线和椭圆曲线的联系,然后构造出一种特殊的椭圆曲线,当且仅当费马大定理不成立时,该曲线才存在。最后,通过证明这种曲线有一些极端奇怪和不可信的性质,决定了曲线不可能存在,从而反证了费马大定理成立。这之中虽然用到了许多前沿的高深数学理论成果才得以证明,但整个思路框架之巧妙,也是让人佩服之至。

编程也是如此,我们首先需要对各种编程方法,编程语言的特性得心应手;而后,编程绝对不是简单的堆砌代码,它需要我们巧妙的构建系统,在合适的地方用合适的方式来解决问题。最终还需要让每个部分都严格正确。

最后,对于那位朋友的问题,我只能给出我的个人建议。学习编程的确需要学习数学。但学习数学,不必列出书目,一本本去啃那些枯燥的教科书。只需要从数学史读起,弄清人类是怎样一步步理解数学的,学习其中的思想,最后用自己的兴趣去研究其中感到有趣的部分。

August 20, 2007

谷歌可以保存搜索历史了

前段时间 google 不能保存搜索历史,让我郁闷了好几天。曾经想办法跟 google 的人沟通了一下未果

今天偶然发现,现在谷歌 又可以记录搜索历史啦,另外还追加了一些功能,比如根据你的搜索推荐一些东西等等。

另外 google 文档不错,啥时候支持 opera 就完美了。

August 12, 2007

欧拉数 e

如果人生有一个终极追求的话,我想那是真理。

一个人的时间是有限的,而真理似乎在无限远处,探索真理需要一代代人的努力,我们靠近一点,就可以让下一代人的起步更接近一些。这可能也是我们的前辈所想所作,所以我们需要学习前人留下的知识。避免又从原点出发。

知识不是数据库中的数据,一个 copy 指令就可以复制出去,永不消逝。书是媒介,大脑才是载体。人类的信息输入带宽极其有限,远低于大脑的处理能力(如果你能善用他的话)。浪费带宽这种稀缺资源是让人痛心的,故而我爱读书。

心情平静的时候读,神情气爽;烦闷的时候读,调节心境;闲暇的时候读,消磨时光;繁忙的时候读,释放压力。我有睡前读书的习惯。昨晚,天气不热,但似乎楼上楼下的人家都习惯性的开着空调。窗外滴滴嗒嗒的是冷凝管滴水的声音。突然想起李清照的两句词来:枕上诗书闲处好,门前风景雨来佳。

这次枕边放的是一本:《什么是数学 》。

早听说这是一本好书,也买了很久了。总静不下心读。前次顺着翻了前面几章,权当催眠读物了。枯燥归枯燥,但我绝对承认这本书写的相当不错。相比许多数学读物,他已经非常生动了。知识点一环扣一环,遵循严密的逻辑推理,而不是凭空跳出一个结论让你接受。或是想当然的认为你应该受过专业的数学训练,承认一些公认的定理和规则。

什么是数学?数学表达的是对象与对象间的关系,而不探究对象到底是什么。它在公理的基础上演绎,而不讨论公理本身的真假。数学是美妙的,作为人类思维的表达形式,反映了人们积极进取的意志、缜密周详的推理以及对完美境界的追求。

学习掌握数学,可以极大的帮助我们洞察这个世界。数学是一种思维方式,而绝不是解题训练。

当反思为什么我一方面喜爱数学,一方面又觉得满是公式的数学书读起来枯燥无比时。我意识到,虽然逻辑推理演绎是缜密而有趣的,但并非人脑天然的运作方式,这个需要后天的训练。当突如其来的逻辑推理需求超过当时接收者大脑可以承受的压力时,必然会导致疲惫和挫折感。也就是处理能力小于信息输入带宽的表征吧。

我的机械记忆力不太好,从小开始,我就拒绝接受没有弄明白的道理。一知半解的东西在脑海中也总是只能暂时停留。以至于我对数学的掌握只能是熟练运用初等数学,而对高等数学粗通皮毛。记得读大学的时候,我的数学老师是全校最好的老师之一。可惜那个时候沉迷编程,觉得了解一点混过考试就够了,错过了学习高等数学最好的时机。大学毕业后,大部分都忘记了。直到前不久,我能记起并运用的微积分与线性代数知识还都是高中时代自学的。现在还依稀记得大学头两年的高数课,老师讲的其实还是满清晰的,也不是填鸭式教学,悔不该当初不多下点工夫真正理解啊。

发自内心的学习欲望,无论从什么时候开始都不晚。

昨天随便一翻书,居然是微积分章节的第一页。这个巧合让我一直读下去。没想到一发不可收拾,直到天色发白,才恋恋不舍的合上书睡去。这时,已经把这一章读完了。

我想起我的数学观念被启蒙前的一些事情,那个时候刚上小学,父亲工作忙,我主要是母亲带着。上学前她教我识字,计数,画画等,但没有特别教给我系统的科学知识。入学后,除了课本上的东西外,没有人强迫我学习更多东西。我记得那个时候自己老是瞎想,比如远近,轻重这些物理概念。说起距离这个概念,可以说是天生自然的诞生的,不需要人教。因为距离是可以直接比画被直觉感觉到的。但是,面积的概念却很难自发的产生。这个问题曾经困扰过我很久,父亲告诉我,矩形的面积就是长乘宽。我接受这个结论,并承认它的合理性,但内心总觉得别扭。虽然我自己从这个结论推导出更多例如三角形面积公式等,但我对其根源却总是心存芥蒂。

有一次我想知道圆的面积怎么计算,在白纸上画了个圆去问父亲。他并没有直接告诉我答案。现在想想,向一个小孩子解释 Pi 应该不是件容易的事情。我继续自己去想:如果能知道铅笔尖的面积,那么我一点点的将圆涂满,数一下用了多少点,应该可以相当于圆面积吧?父亲看我不停的在纸上戳点,问出我的想法,笑着说,原来我儿子这么小就懂微积分了 :D 当然,向小孩子解释什么是微积分是很困难的。那个时候父亲一定跟我解释过,不然我不可能对这个名词记得这么清晰。但是我也肯定没弄懂。

后来我知道,求面积其实是一种积分(积累微小的分片、我这样理解这个词)的过程。学会抽象思维后,我不再对矩形面积公式介怀。

这些亲身经历的故事告诉我自己,无中生有的构造出新的概念,对于一个没受过数学训练的人不是件容易的事。新的知识一开始应该给人有直观的感受,才容易让人记忆深刻。逻辑、分析、构作,则可以加强这些记忆并接受它们。


其实原本是想谈谈 欧拉数 e 的。跑题太远了,谁让我是在写 blog 呢,无所谓了。

e 是一个很出名的数字,但在大众,远不如 Pi 来的有名。它不够直观,不像 Pi ,可以表示半径为 1 的圆的面积。

有一年校园招聘的时候,面试一个数学系的本科毕业生,我的同事提了个问题:什么是 e ?未能听到满意的答案。

是啊,我们知道科学计算器上总有个按纽上标着 ln ,说明书告诉我们它可以用来取以 e 为底的对数;大多数计算机编程语言的数学库中总会提供一个 exp 函数,用于求 e 的幂;中学老师告诉我们 e 是自然对数的底;e 是 2.718281828459 ……

但是 e 到底是什么?。可为什么要选择这么一个特殊数字命名为 e ?书本上一定讲过、课堂上许多老师也讲过,可还是很多人事后忘记了。我在这里再谈一次不为过。

跟 Pi 一样,e 也可以从几何上给出一个直观的表示。不过这个图形没有圆那么容易画出来。我们需要作 f(x)=1/x 的函数图象,是一个双曲线。在第一象限,从 x=1 到 x=e 之间,曲线和坐标轴之间所夹的面积正好的单位 1 。

这样的几何上的描述对并不够有说服力,因为它只是诸多函数图象中的一个,没有什么特别。下面我们得看看, f(x)=1/x 这个函数的特殊之处。

如果你认可微积分在现代数学中的重要地位,那么就会发现,对多项式求导是研究各种问题的一个重要手段(比如在经典物理学中,研究速度、加速度、距离等之间的关系)。借助初等数学的推理,我们就可以得到对多项式求导的公式(这里就不展开列出了,但是这些推导过程对理解微积分很有帮助,而且仅需要初等数学知识就可以做到): x ^ n 的导数为 n * x ^ (n-1) 。

反过来,x ^ n 就是 x ^ (n+1) / (n+1) 的导数。这种逆运算,被称之为不定积分。

btw, 诚如《什么是数学》书中所述:简单地定义“不定积分”为导数的逆运算,这种做法是把微分过程直接和“积分”这个词结合起来。然后引进作为面积或者和的极限的“定积分”的概念,而不强调这里“积分”这个词指的是完全不同的东西。会大大有碍于学生的真正理解。我个人也是很反感强加的概念:直接定义这种逆运算规则是让人不可接受的。其实这其中隐示的东西,正是牛顿和莱布尼兹为数学做出的杰出贡献。是他们首先把前人已经为积分和微分上做出的工作结合在了一起,思想上做了统一。这里不展开讨论微积分,仅仅只是不想离题太远而已。

当我们考察 x ^ (n+1) / (n+1) ,当 n=-1 时,分母为零,公式将失去意义。那么对 x ^ -1 即 1/x 的积分会引出怎样一种函数,就变的非常有趣了。以下,我们就直接用 ln x 来表示对 1/x 从 1 到 x 的积分。而 ln x 的导数则为 1/x 。

根据微积分中的基本定理(可直观的用初等数学方法证明的定理),我们可以得到若干对数运算的法则。又因为 ln(x) 是 x 的单调连续函数,当 x=1 时值为 0 ,且 x 增大时趋向无穷大,这样,就必定存在一个大于 1 的数,当 x 取此值的时候 ln(x) = 1 。

这个数值就是被欧拉称之为 e 的东西。

当我们考察 y=ln(x) 的反函数、即 x=exp(y) 时,会发现 exp(y) 这个函数的值在 y 为有理数时,和 e ^ y 的值总是一致的。这一点并不难证明。既而很容易得到幂函数的公式 e^a * e ^b = e^(a+b) ,且可证明它对任意有理数或无理数皆成立。

整个研究过程,从对数推导出幂函数,从自然数推导到有理数再到无理数,借助微积分这个工具的帮助,都很容易的走过来。这样的过程,在中学时,老师则是从整数幂 a^n 开始,定义 a^(1/m) 的意义,从而将幂函数推广到有理数集。两种推导方式向比较,中学时我们学过的初等数学的方法就不那么逻辑缜密了。这里面微妙的地方在于,初等数学借助一个想当然的定义跳过了逻辑的断层,而微积分就是来弥补这个裂痕的。虽然微积分的解释得花更多的脑力去理解,但它可以充分让我信服。

在这些讨论中,对数函数和指数函数都是以数 e 为“底”展开的,所以我们也把 e 称之为对数的“自然底”,或是“自然对数的底”。继续把底数 e 推广到任意正数的变换是容易作出的,而 e 则是变换的根本。

e 在其中的地位,好象 1 在自然数中的地位一样。虽然日常我们用 10 进制计数,但 2 进制却只用 0 和 1 ,即无和有两个概念,就衍生出了一切。其余的符号都是冗余。现代计算机广泛应用 2 进制之前,莱布尼兹就已经对二进制推崇倍至。我们可以把 10 进制记数规则看作是 2 进制的一种衍伸,人类选择 10 进制只是因为碰巧生了 10 个指头而已,而 2 进制则是永恒存在的。

最终,由微分法则我们可以得到一个奇妙的结论:以 e 为底的指数函数的导数就是它自身,即自然指数函数与它的导数恒等。这一点,实际上是指数函数所有性质的来源,并且是它在应用上之所以重要的基本原因。


ps.以上的文字并没有涉及具体的推理和证明,那需要相当的篇幅。但我觉得期盼得到高等数学真谛而未入其门的朋友都值得去找出书来读懂。这些过程用初等数学的知识就可以理解。

最后忍不住再提一下“素数定理”。它由高斯发现,并被誉为整个数学中最著名的发现之一。

至今人类未能找出一个产生所有素数的简单公式,也没有找到求前 n 个自然数中所有素数个数的简单公式。但是考察素数在自然数中的分布规律时,却找到了些许规律。

高斯发现,在自然数 n 极大时,n 与 n 之内素数个数的比值,近似等于 ln (n) 。n 越大越接近。不过前者是两个自然数的比值,是一个有理数;而 ln (n) 是一个无理数。两者只会无限接近,而永远不会相等。

素数的分布的平均状态居然可以用对数函数来描述,这太有趣了。两个似乎无关的数学概念在事实上竟有如此紧密的联系,真是让人拍案称奇。

August 06, 2007

读了 google 的几篇论文

周末在家赖床,把玩我的 treo 手机,从 google reader 上看到 myan 大大新近介绍 google 的三篇论文的中译版

(插一句,google reader 的手机版做的相当不错,很烂的手机都可以方便的使用,界面简洁,节省 GPRS 流量,强烈推荐)

这三篇论文我都有所耳闻,GFS 的论文应该出来最早,前几年就有同事发过英文版的给我看过。MapReduce 耳边经常有人跟我提起。BigTable 听的比较少一点,但也知道大概是咋回事。

三篇论文中译本都没读过(更别说英文版我会仔细学习了)。我便躺在床上,捧着手机,细细品读。

这三篇其实都是解决大数据量,分布式处理的问题。说穿了,都没什么技术难点,也无啥革命性的技术创新,但系统实现起来绝对不简单。这个难度,体现在工程实现上的困难。

健壮的系统总是结构简单规则简单的,用冗余的数据提高效率,增加健壮度。

GFS 是另两个系统的基础,它最底层利用本地文件系统提供原子操作,而不是自己解决。这可以简化系统复杂度,我们在设计系统时就应该尽量简化每个层次上代码完成的工作。与之类似的,我在设计我们的游戏服务器架构的时候,数据储存一块没有使用标准数据库,而是依赖于内存与本地文件系统,也是基于这种考虑。

GFS 采用了单点的 master 调控全局,这样可以做出非常简单的设计。但是需要极度减轻加在其上的工作,最终让 client 在真正获取数据的时候不必直接和它通讯。我非常认同这一点,有时候设计一个单点总控的单元并非不合理。我们已经实现的登陆服务器就是这样的,用户只有一个登陆认证点,但认证完毕后不再需要保持连接。

整个系统中,其实可以有许多单元是单点的。只需要减轻其上任务的复杂度,往往都是可堪负荷的。至于单点故障的问题,在底层设计上可以允许发生错误并重试,而系统能够快速重启就够了。当然,并非系统所有的部分都适用,有些地方,相互备份的模块是必须的。

BigTable 满有意思的。我认为当初做出设计的最难点是合理的提出需求,把需求简化到最小的单位,然后就最基本的需求来实现和优化,得到一个高性能的分布式结构化数据存储方案。

比如完全的关系数据模型就是不必要的,但是版本控制就有必要。复杂的数据类型是没有必要的,只需要储存字符串就够了。合理的需求自然需要大量的实践经验来总结,而需求的合理则可以做出极大的性能优化。实现者最清楚怎样的需求能最大限度的优化;实践者最清楚哪些需求是合理的,必须的,哪些则是不重要的,可放弃的。我们对系统设计者的要求就是即有丰富的实践经验,又有足够的能力自己做实现。这样才能做出优秀的系统来。

最后说说 MapReduce ,原理不复杂。就是把大部分可分布式任务完成的要点提取出来:即数据分割、分布式叠代处理、去掉冗余的计算结果、结果合并。效率的提高在于冗余处理,用廉价的机器计算能力来减轻系统设计的复杂度。系统则专注于解决数据传输、分割、合并这些简单逻辑的高效实现上。并实现数据定位和数据运算的正交化。


以上我也就是简单评论几句,行家不必较真。目前我的工作范围内尚没有需求去设计实现类似的系统,所以暂时也没太多精力研究细节。我相信若真的做起实现来,困难会很多,工作量会很大,会碰到相当多初期没想到的难题。

随便再写几句最近的一些工作。

新同事报道,安排的工作是完成我前段做了一半的资源管理模块。几个月前,我那段代码几经修改后算是收工了,提交代码仓库后就没有修改过。但是我只完成了从本地文件系统中加载资源,这次打算把数据打包以及数据包读写的加上。

大约花了好几天的时间讲解代码和设计,也算新同事天资聪慧,硬是把我近千行毫无注释的代码给理解了一遍。想起有些地方很不规则的内部函数命名,以及偶尔几行自己都差点想不起的原始设计用意,真是汗颜。

最后,总算让人弄懂了,自己也输理了一遍当初的思路。值得庆幸的是,设计大体还算合理,这次新添加东西没有动任何老的接口,也没有新增加接口。该隐藏的信息都隐藏好了,该暴露的东西都用上了。新添加的代码跟老代码的正交性也还好,不大需要重复做一些工作。

表面上看起来应该很简单的东西,实际做出来还是满复杂的,我想这就是工程实现的难度吧。

August 05, 2007

人民币升值?

大约是零三年的时候,我的银行里有了一笔美金,出于游戏心理,我开始炒实盘外汇。同时开始关注世界几大货币的汇率变化,以及黄金价格。那个时候,人民币保持对美圆的固定汇率,8.27 。美圆对欧元 1.1 到 1.2 左右,对英磅 1.6 到 1.7 ,对日圆 110 到 120 。那一年我第一次出国,去澳洲公干,美圆对澳元是 0.6 左右。

从那个时候起,我对货币本身产生了浓厚的兴趣。

零四年第一次去美国,大约住了一周。人民币在那一年依然坚持盯住美圆,保持 8.27 的汇率。但是互联网上已经充斥着人民币即将升值的消息。在美国的那些天,我逛过超市、租过车、去过几种档次的餐厅、喝过当地的星巴客咖啡、打过公用电话、也跟当地居住的朋友聊过天,算是对那里的生活消费水平有了个很初步的了解吧。晚上在酒店里,由于时差的原因不能入睡,便从走廊上的自动售货机中买了罐可乐、50 美分,开始躺在床上胡思乱想。

离开美国的时候,我的时差还是没倒过来,当时到底想了些什么现在也记不清了。但是有一点我记得很清楚:经过了一番推理,我预感到到人民币一定会升值,而且伴随着人民币升值的一定是极大的通货膨胀,人民币购买力下降。

回国以后,我在不同场合,跟不同的朋友同事说出我这种感觉。后来零五年我再次去美国时,没再想这些问题了,我以为这些是理所当然的事情,发生只是迟早的事,我对自己的猜测更为坚定。

零五年下半年,准确的说是2005年7月21日,国家突然宣布人民币对美圆升值到 8.11 ,当日升值 2% 。那一天我很有印象。那个时候我跟几个同事正在出差,一个同事看了个短信后跟我说“亏了亏了”。他刚好行使掉公司的期权,美刀还没有汇到国内,就这样平白无故的在一天之内蒸发掉 2% 。让他更为忿忿然的是:那笔钱原本可以早两周办好手续的,可正碰上 CFO 度假,耽误了在文件上签字。

我在同事对公司头头们的抱怨中想起头一年思考的那些问题,觉得事情开始应验了。

前段去泰国玩,购物刷的信用卡,以美圆结算的。回国后一看帐单,现在人民币已经升值到 7.6 了,还有收不住的势头。而这些时候不断的传来消息,商品房涨价了,汽油涨价了,猪肉涨价了……

晚上跟当年曾一起讨论过人民币问题的朋友再次聊天时,回想当年的谈话,唏嘘不已。虽然人民币还没升值到当年我预期的价位,物价的涨幅也还没到我的预想。

但,事情终究发生了。


我当时的逻辑其实相当简单:

首先,中国在国际贸易中占据的极大的位置,在欧美市场上,来至于中国的商品绝不少见。而在国内,随处可见进口产品。世界经济一体化的进程越来越快。

在美国,以 8.27 的汇率计算,日常生活的物价水平折算成人民币,大约是国内的两倍。也就是说,单以表面上的货币的购买力来看,人民币的购买力在生活中是要高出美刀许多的。

美国是中国最重要的出口市场,中国有大量的出口产品销往了美国市场,造成了极大的贸易逆差。而这些交易,大多以美圆结算,最终导致中国有太多的美金储备。

美国是一个比中国大很多的经济体,金融工具比中国完备很多。如果用金融手段对中国发起战争,中国不可能是他的对手。

最终,人民币在生活中,表面上看起来的购买力会逐渐的趋向跟美圆相同。这有三种手段可以达到:一是人民币对美圆贬值,二是美圆升值,三是人民币在国内由于通货膨胀而购买力下降。

人民币对美圆贬值,由于国际经济和政治因素,几乎不可能达到。中国的经济系统远没有美国成熟,经济发展过快,加上一些方面的畸形快速发展,而基础建设并没有跟上,这些都是货币的不稳定因素。反倒是,国内通货膨胀的可能性要大很多。

由于中美贸易逆差,以及中国庞大的美金储备,美国的经济体非常希望人民币升值,这样可以带来巨大的利益。一旦付出行动,中国央行压力就会很大。简单的人民币对美圆快速升值,会使国家的美金储备价值急剧下降。这个损失不可能一直由政府或一些小的强势团体买单。另一方面,人民币的直接升值,会使其购买力进一步上升,这与前面的结论相悖。

当大众把购买力上升的储备货币投入市场,购买有实际价值的商品以期保值时,流通的货币快速增加,而我们的实际生产能力并没有相应的增加,通货膨胀就自然产生了。

一直以来,中国的储蓄比例都是相当的高的。这并不是一件好事。因为可以被储藏的社会财富并不多,而货币本身并无价值,货币总体可以承担的财富保值的总量,不可能超过社会本身可以储存实际财富的总量。社会发展,最终靠的是基础建设,提高资源的利用效率和生产效率;需要完备的金融工具调配社会财富。

当我们向海外低价倾销商品时,我们很可能在低价变卖自己的劳动,放弃本属于自己的财富。最终,在货币的变动中,一切化为乌有。

今天,美元对欧元 1.38 、对英镑 2.04 、对日元 118 、对澳元 0.85 、对人民币 7.56 。