Nov 17, 2008 - 编程珠玑番外篇-4. Linux 下的 Facade 程序

Comments

Linux 下的命令行工具大致有两个流派, 一是以小而精见长的, 只能提供一个简单的小功能. 比如 yes 这个命令, 除了输出一大串永不停止的 y 之外毫无用处. 这个工具看上去土, 很没用处的样子. 碰到要你一路回车法的时候, 这个工具就大大的有用. 所以我每次帮人使用一路回车法装 windows 的时候, 就怀恋 Linux 下的这个 yes. 过一个管道, 就省去了在电脑面前按下几百次 y 的繁复工作. 

还有一种工具, 是我今天要说的重点. 这种工具一般是一个简单的命令行调用, 却有着几十种甚至上百种不同的参数的组合, 用这些参数能搭配出谁也没用过的功能. 以 gcc 为例, 居然有两百多个不同的命令行参数, 范围涉及到程序编译, 连接设置, 库设置, 优化, 报错信息, 调试信息等等, 任何一个正常的人想要穷尽学完这些参数都是不可能的. 同样的库还有 convert (图像转换的), ffmpeg (视频处理的), curl (内容抓取的). 看上去这些参数指示的功能乱七八糟的堆砌在一起的样子, 仔细一想这些功能的确是相互关联的, 所以被放到了一个工具之下. 这些工具和上面的工具的哲学是反其道而行之的: 集一大类功能于一个工具, 任何类似的操作都能通过这个一个命令+不同的参数来完成, 而非”do one thing, do it well”. 这些工具和传统意义上的 UNIX 工具哲学是不大像的. 为了区分他们, 我把它们叫做 Facade 工具, 因为这些工具的设计哲学很类似于 Design Pattern 里面的 Facade Pattern (Facade 模式的核型是用一个统一的接口管理对一个系统的访问. 比如 gcc 就是对整个编译系统的接口, ffmpeg 就是对整个视频处理系统的接口, display 就是对整个 X 显示系统的接口等等.)

之所以区分这两者, 是我体会到: 在具体的学习过程中, 对付两者的学习方法是截然不一样的. 学习小工具, 基本上就是学一个简单的名字到功能的定义, 加一些简单的参数. 除了名字比较别扭外, 使用很方便, 学习曲线不陡峭. 学习的要点不在于这些小工具本身, 而在于利用管道和其他工具通信(小工具从来就不是单独使用的, 比如 yes, 比如 tr, 我几乎没见过不用管道的情况下用他们的); 和上面相反的是, 我几乎没见着 Facade 工具用在管道里面的.

原因是 Facade 工具基本上是一个自成体系的完整的操作方式, 就像一个新的领域的一种新的”语言”一样. 因此, 不掌握一点基本的编译知识, 就不可能把 gcc 玩转, 因为那些参数的含义的理解, 都是需要相应知识的. 我也常常看到不少 做 Web 程序的哥们对 curl 的每个边边角角都很熟悉, 但是对 gcc 不太熟, 这也是很正常的, 因为 Facade 程序本来就是属于面向一个特定领域的工具. 

我在学习这两种截然不同的工具的时候也曾感到过困惑: 怎么有的程序这么多参数, 全学会怎么可能. 在浪费了不少时间乱看这些 Facade 程序的 man 文件之后, 我认识到: 除非我写操作系统, 要让我的程序编译的时候有几百个参数, 否则, 简简单单的用 gcc 常用参数就能解决99%的问题了. 我觉得, Facade 程序的要点正是在于, 用一些简单的参数组合(更多情况下其实不要参数) 就可以完成 90% 的常用例子. 至于剩下的 10%, 遇到了再去查文档就行了. 同时, 对于不在自己”常用工具集”中的一些 Facade 工具, 认真学习他们的用法是一件非常耗时且几乎没有任何收获的事情, 而且学到的也不会被实际用到. 所以, 千万不要被”获取新知识的成就感” 给蒙蔽了, 去钻研那些琐碎的边边角角. 

而对于小工具, 却要反过来. 我觉得在学习小工具 (尤其是 coreutils 里面的所有命令) 的时候, 最好要做个有心人, 把大部分参数弄清楚记住 (本来参数也不多). Linux 下的小工具基本上是千锤百炼经过无数进化的, 应该说每个选项都是很常用的. 搞明白这些选项, 可以极大化发挥这些小工具的优势, 还能提高自己的生产率. 举个例子: 比如说 ssh 这个程序, 90% 的哥们就是用他来登录服务器, 然后运行服务器上的某个程序. 其实 ssh 的文档写得很清楚, 你可以把 ssh 后面接一个命令文件. 比如说 

ssh name@server.com ls

就可以直接显示服务器上的目录了. 还可以拓展一下, 

ssh name@server.com < script.py

就可以直接把本机上的 script.py 放在服务器上跑, 无需把文件先拷贝过去. (走题一下: 跨平台的脚本语言的好处就在这里. Apache 的 Hadoop 是 MapReduce 的一个开源实现, 他的任务控制器就是采用我说的这种方式来调用各个机器上的Mapper 或者 Reducer 工作的). 因此, 掌握 ssh 的加命令的用法, 在我看来, 是值得的.

很多小工具都有这样不太鲜为人知的用法, 熟稔这些用法, 我觉得是值得的, 况且这也不需要花多少时间, 只要打印一份文档每天睡前看半页就行了.  我以前还有整理了不少这类平时大多数人注意不到的小命令的一些”黑魔法”. 我觉得这些黑魔法一点都不是什么奇技淫巧, 而是实实在在能提高效率的魔法, 是居家旅行必备的工具套装. 

PS: 最近有几个朋友看了我的博客, 发信让我推荐学习 Linux 的书. 我推荐 “鸟哥的Linux私房菜” 这本书. 我学 Linux 的过程中没看过这本书, 所以折腾的比较曲折. 直到我大四我才看到这本书, 这本书是一本非常深入浅出的好书. 

PS2: GNU 的工具链有把小工具 Facade 化的倾向. 连 ls 这么简单的命令都有几十个参数. 在这种情况下, 还是挑选一些认为会常用的参数学习一下就行了, 没有必要去追求高大全. 一般说来, 这种两个字母的小工具, 如果后面加的参数超过6个字母, 就完全不对味了. 工具这东西, 强极则无用至极. 

-EOF-

Nov 13, 2008 - 编程珠玑番外篇-3. 关于程序优化的八卦

Comments

(把八卦和文章重新分了一下类, 准备围绕自己的心得写个编程珠玑番外篇, 这个算第三篇吧)

<代码大全> (Code Complete) 是一本很好的书. 我建议像我这样写的程序总行数不超过50万的程序员应该买一本放在案头 (当然<代码大全> 不如 这本书好, 这个我以后有机会写文章细谈) 如果你天天编程序, 我建议你买一本. 如果你已经有了<代码大全>, 我诚心建议你赶快翻开此书, 撕去第26章. 因为代码大全的其他章节可以让你成为优秀的程序员, 唯独第26章, 读了之后立即从优秀程序员变成最差的程序员. 为啥? 因为第26章讲的, 都是怎么调节代码使得代码跑得更加快的技巧, 而这些技巧, 几乎都是让一个好程序变成差程序的技巧, 是教你不管三七二十一先对程序局部优化的技巧. 而局部优化是让程序变得糟糕的最主要的一个原因. 用高爷爷的话说, 提前优化是万恶之源 (Premature optimization is the root of all evil). 这些技巧, 就是带你去万恶之源的捷径. 代码优化究竟是什么洪水猛兽, 又究竟有多少伟大的程序员因为代码优化声名扫地, 请看本期关于代码优化的八卦. 话说当年在贝尔实验室. 一群工程师围着一个巨慢无比的小型机发呆. 为啥呢, 因为他们觉得这个机器太慢了. 什么超频, 液氮等技术都用了, 这个小型机还是比不上实验室新买的一台桌上计算机. 这些家伙很不爽, 于是准备去优化这个机器上的操作系统. 他们也不管三七二十一, 就去看究竟那个进程占用CPU时间最长, 然后就集中优化这个进程. 他们希望这样把每个程序都优化到特别高效, 机器就相对快了. 于是, 他们终于捕捉到一个平时居然占50% CPU 的进程, 而且这个进程只有大约20K的代码. 他们高兴死了, 立即挽起袖子敲键盘, 愣是把一个20K的C语言变成了快5倍的汇编. 这时候他们把此进程放到机器上这么一实验, 发现居然整体效率没变化. 百思不得其解的情况下他们去请教其他牛人. 那个牛人就说了一句话: 你们优化的进程, 叫做 System Idle. 所以说. 优化这东西, 一定要有一个全局的思路, 否则就是纯粹的无用功, 有时候还是负功. 在<编程珠玑 II=""> 第一章, Jon Bentley 就着重提醒了代码 profiling 的重要性. 说到 profiling 这个词, 就不能不再次提到万众敬仰的高爷爷. 高爷爷在1970年的暑假, 通过捡Stanford 大学机房扔出来的垃圾(其实是含有程序的磁带), 写出了一篇震古烁今的论文 “An empirical study of FORTRAN programs” (FORTRAN 程序的实证分析). 除了抱怨写程序的人不看他的 TAoCP 之外(因为一个程序用了被高爷爷定性为史上最差的随机数发生器算法, 有兴趣的可阅读 TAoCP vol2), 这篇论文主要说了三个划时代的东西: > 1. 对程序进行 profile 是每个编程系统的居家旅行必备. > > 2. 在没 IO 操作的情况下, 一个程序中 4% 的代码占用了超过50% 的运行时间. > > 3. 97% 的情况下对程序进行提前优化是万恶之源. 这三个道理, 用大白话说, 就是: 1 程序都存在热点, 有优化的空间. 2. 但是97%的情况下程序员优化的都是错的地方, 反而把程序优化糟了. 3. 想要做优化, 第一步就要先知道程序在什么地方耗时间而不是靠猜. 说到热点, 顺带拐八卦一下Java的速度. Java 1.5 的虚拟机的关键技术, 就是叫做 Hotspot (热点). 传统上, 大家都认为 Java 比C 要慢. 其实不然. Jython 的作者 Jim Hugunin 就曾经说过, 其实两者差别不大 (http://hugunin.net/story\_of\_jython.html). 也有一些其他的测评说, Java 比 C 要快. 原因就在于, Java 虚拟机能够找到热点, 对热点专门做优化. 而C程序编译好了, 即使有热点, 也只能靠CPU去优化了. Java 的优化比 CPU 要深且更全局. 言归正传. 关于 FORTRAN 的 profile 的传统被继承了下来, 基本上现在任何的过程式主流编程语言都支持 profiling 工具. 关于 profile 怎么做的问题, 等我有空了好好写文章介绍. (因为我发现, 除了编程珠玑, 没有一本书提到过). 做程序优化的八卦就太多了, 说一个Beautiful Code 上的吧. 话说世界上做线性代数的库叫做BLAS, 基本上是工业标准. 因为线性代数运算太重要了, 所以各大处理器厂商都有 BLAS 的实现. Intel 的叫 MKL, AMD 的叫 ACML. 矩阵乘法实现的好坏, 直接决定了处理器的性能测试的分数(因为现代测处理器的速度的程序, 比如LAPACK指数, 基本上都是用 BLAS 里的矩阵乘法做基准). 去年 nVIDIA 高调宣传自己的 CUDA 系统比CPU厂商快10倍到100倍, 借此打开了GPU计算的大门(令人发指的达到500GFlops, Intel 最新的只有50GFlops). 其中 CUDA 可以理解为是 BLAS 在 nVIDIA 平台上的实现. 自从nVidia 推出 CUDA 以后, 俨然不把 intel 这些厂商放在眼里, 心想, 小样, 你们还是做通用处理器吧, 浮点乘法这些高级的东西, 还是放在显卡上比较好. nVidia 和 IBM/SONY 的阴谋很不小呢. 要是浮点计算比 Intel 快这么一两个数量级, 以后世界上前五百名超级计算机就全部变成什么用光纤网连起来的 PS3 机群, nVidia 显卡机群之类的. 人家外行见了计算机科学家肯定要问: 你们搞高性能计算机究竟是搞计算还是打网络游戏啊?? 还是言归正传(我怎么老走题?), 简要的说一下 BLAS 优化. 单处理器上对 BLAS 的优化主要体现在对 cache 的高效使用. 矩阵乘法中, 如果矩阵都是按照行存储, 则在A*B中, 对B的访问是按列的. 假设B一行有N个元素, 那么在存储器中, 两个同列不同行的元素所在的存储单元相差N. 因此, 对B的访问并不是局部化的. 因为访问不局部化, 所以每次乘法, 都需要从内存中调一个 cache 单元到CPU. 这个极大的降低了处理器的执行速度. 因此, 矩阵乘法的优化的核心, 在于局部化B的访问. 反过来, 如果矩阵按照列存储, 则要局部化对A的访问. 关于怎样局部化访问还能获得正确的乘法, Beautiful Code 一书的第14章有非常好的讲解, 我就不废话了. 总之, 矩阵乘法局部化的好坏, 取决于一个机器的 cache 的大小. 多处理器和向量处理器就又不一样了. 要想利用好, 就要把计算任务平均的独立的分到不同的处理器上. 所以, 在这里, 优化就变成了分解成若干的小问题. 因此, 分治算法成了主流. 具体矩阵乘法怎么分块, 大学数学都讲了, 我就不废话了. 事实上, 之所以 nVidia 能和 Intel 干, 就是因为显卡上令人发指的有 64 个计算核心, 而 Intel 最牛X的才 4个. 那为啥 Intel 自己不多做几个核心呢? 因为 Intel 自己把自己带沟里去了 — Intel 处理器太复杂支持的功能太多了, 一块硅片上根本放不下很多核心. 而 nVidia 一直就是专用处理器, 每个核心功能简单, 可以做到很小. Beautiful Code 第14章就是讲了随着计算机体系结构的变化, BLAS 是怎么进化的. Tanenbaum 曾经说过, 随着一个科技的出现, 某个 idea 可能就销声匿迹了. 但是说不定下一波科技再来的时候, 这个 idea 又复活了. BLAS 从串行, 到向量, 再到串行(带cache的RISC), 再到向量(Cell), 就是一个绝好的例子. 对这个进化史感兴趣的读者不可错过这一章妙文.

Nov 9, 2008 - 工具的强是无敌的-2

Comments

以前写过一篇文章, 叫做 <工具的强是无敌的>, 这是上文的续篇. 

话说在国内的时候, 都是过校园生活. 除了值日和把衣服送到洗衣机旁边再投两个币之外没有所谓的家务事. 爸妈也很娇生惯养我, 在家也不怎么干家务事. 所以除了偶尔洗个盘子扫个地, 基本没啥事情.  在这里就不一样了, 啥事都要自己来, 吃完饭盘子终归要洗, 地板终归要自己清理, 衣服享受不到老妈洗好叠好的优待了. 当然我也不怎么嫌麻烦, 反正马马虎虎的洗洗碗拖拖地也不觉得麻烦, 况且一周就一两次 :). 这基本上是我第一年生活的概括. 

第二年要结束的时候, 我认识了现在的女朋友. 她是典型的美国人, 来自有洗碗机和吸尘器的家庭. 所以从来不需要用手洗碗, 也不需要拖地. 她住过来之后, 就一直怨念: 没有洗碗机没有吸尘器, 这日子还怎么过啊… 我听了特感慨: 唉, 资本主义和社会主义就是不一样啊.  老怨念也不是办法, 所以只好值日一样轮流洗碗. 在她的态度的影响之下, 我也觉得美好的人生被洗碗浪费了, 于是, 新找了一间新的房子, 有洗碗机的房子. 下月搬过去. 洗碗的故事基本上告一段落.

拖地的故事是我要说的重点. 我们平时都不在家, 所以老忘记给地板吸尘, 地上脏兮兮的. 她上周看到网上吸尘机器人 Roomba 促销, 立即就怂恿我买一个. 于是, 两百多块大洋下去, 买了一个自动吸尘的机器人. 这个自动吸尘的机器人可以自动定时打扫房间, 还能自动回到”基地”充电. 因为这个机器人非常好玩, 像昆虫一样在屋子里面走.  还真别说, 有了这个机器人之后, 家里面天天有”人”打扫, 干净多了. 而且据说这个机器人是可编程的, 等有空试试. 我和女友开玩笑说, 就差洗碗机上来一个机器手臂了, 这样你连放到洗碗机都不需要自己动手了. 她说, 还要有自动做饭机器人才行…

除了拖地, 我以前在文章中也提到, 我们家的空调和暖气是可以远程控制的. 上个月我又花了10块钱不到淘了一个可编程的温度控制器, 和计算机控制暖气的系统连起来, 我家现在算得上四季如春了. 还有我平时很少看电视, 但是每周六的SNL是必看的, 所以计算机设置让电视周六晚上10:59打开, 也不需要自己老是看时间怕错过节目了. 

除了用 X10 协议控制家电和使用吸尘机器人之外, 我家还有不少其他的工具, 都是我女朋友带过来的, 比如一整套量调料份量的工具, 一整套清洁耳朵的工具, 一整套自动定时对电视节目录制和去广告的工具等等. 不过我也不大常用, 她倒是完全依赖于这些工具, 量 1/3 匙的盐, 2.5杯水, 录周一7点钟的 Heros 等等, 都是被她用得滚瓜烂熟的工具. 在她这个资本主义国家的人面前, 只能感慨自己完全没有技术含量.  

说了这么多, 还是一个中心: 工具的确能帮人节省不少时间, 让人从繁重的劳动和对琐事的管理中解放出来. 工具的强是无敌的. 或许, 最好的投资是投资学习, 次好的投资是投资工具, 其次才是买蓝筹股和买股票.

Nov 5, 2008 - 也就100年

Comments

Obama 当选总统了. 撤军, 加大对科研投入, 减税等等, 对我们这些在美国的学生是一件好事情. 

在赢得胜利的演讲中, Obama 说到了一个106岁的修女 Ann Nixon Cooper 的故事,

“She was born just a generation past slavery; a time when there were no cars on the road or planes in the sky, when someone like her couldn’t vote for two reasons — because she was a woman and because of the color of her skin. And tonight, I think about all that she’s seen throughout her century in America — the heartache and the hope; the struggle and the progress; the times we were told that we can’t, and the people who pressed on with that American creed: Yes we can. 

At a time when women’s voices were silenced and their hopes dismissed. She lived to stand up and speak out and reach for the ballot, yes we can;

When there was despair in the dust bowl, and depression across the land, she saw a nation conquer fear itself with a new deal, new jobs, a new sense of common purpose, yes we can.

When the bombs fell on our harbour and tyranny threatened the world, she was there to witness a generation rise to greatness and a democracy was saved, yes we can.

She was there for the buses in Montgomery, a bridge in Selma and a preacher from Atlanta who told the people that we shall overcome, yes we can.

A man touched down on the moon, a wall come down in Berlin, a world was connected by our own science and imagination and this year, in this election she touched her finger to a screen and cast her vote, because after 106 years in America through the best of times and the darkest of hours she knows how America can change, yes we can. ”

(她是废除奴隶制后的第一代人, 是个没有汽车和飞机的时代. 因为性别和肤色,  她没有投票权. 今晚, 我思考着她观察到的一个世纪的美国–心痛和希望; 抗争和进步; 从我们被告知我们不能改变, 到今天, “我们可以” 成为美国人的信条代代相传的信念.  

当妇女的声音不能被听到, 当希望被剥夺的年代, 她站起来, 为妇女的投票权抗争: 我们可以. 

当大萧条弥漫这个国家, 当黑风暴带来绝望的时候, 她见证了这个国家用新政, 新的工作和新的公共福利战胜恐惧. 是的, 我们能! 

当炸弹在珍珠港落下, 当暴政威胁整个世界, 她见证了一代人的伟大, 见证了民主被捍卫. 是的, 我们能! 

她见证了在蒙哥马利种族隔离的公共汽车, 见证了在民权运动的起源地, 见证了那个亚特兰大牧师(MLK)对人们说: 我们终会克服这些. 是的, 我们能!)

我最爱的小说是<百年孤独>, 一百年后的拉丁美洲和一百年比, 一场大洪水之后什么都没剩下; 而在美国, 100年, 足可以让一个没有人权保障和普遍选举权的国家, 变成一个民主自由的世界灯塔. 也就100年. 

一个国家的下一百年, 是走向百年孤独, 还是走向自由民主, 值得我们深思. 也就100年, 我们同龄的大多数人至少能见证70年, 70年过后, 回问自己: 在被别人告知不可以的时候, 你是什么也不做, 还是握紧拳头在心里和手掌心都深深的刻下: 我们可以改变. 

改变一样东西, 100年足够了. 别信什么一万年太久, 只争朝夕, 那也是谎话. 别着急, 也别绝望, 用切实的行动, 改变我们这个世纪.