Category: Develop

40 posts

Hadoop 实战:谁是最倒霉的人?

上一次介绍了 MapReduce 的工作方式以及 Hadoop 这个开源的 MapReduce 实现,这次尝试用 Hadoop 来写一个简单的应用。要解决的问题是这样的:现在我手里有大量的邮件数据,并且我知道每封邮件是正常邮件还是垃圾邮件,现在我想要找出收到的邮件中垃圾邮件最多的人,亦即找出“谁是最倒霉的人”。 首先是 Map 的过程,输入数据是一封一封的邮件,彼此之间没有任何关联,因此可以很自然地分组处理。Map 将邮件转化到以邮件的收件人进行分组,如果邮件是垃圾邮件,则映射到收件人的垃圾邮件数“+1”。Reduce [...]

public interface RequestProcessorFactoryFactory

曾经在 reddit 上看到这个 Apache 的 FactoryFactory ,觉得很好笑,只是想,大概这样的名字就是严格按照某些设计模式做出来的吧。不过笑过之后也并没有去细想。 最近自己开始用起 Java 来,因为以前学过这个语言,所以很容易就上手了,之后差不多很多东西都很自然,直到有一天我发现自己不小心做了一个叫做 FeatureCollectionFactory 的接口出来,才觉得似乎是该好好想一想了。 有一些东西,自己以前也时常听到或者看到,但是觉得太“企业级”了或者太“Java”了,并没有去关注。比如 Factory 这个东西,为什么会需要 Factory [...]

程序优化中的测不准原理

在《The Art of Computer Programming》一书中有这样一句话: Premature optimization is the root of all evil in programming. 相信大家肯定都已经耳熟能详了,也大都清楚我在“Ruby: 提升性能的几点尝试”中提到的优化程序应该走的基本步骤。虽然如此,这样的情况还是时常发生:花力气把代码大改一番之后发现性能并没有得到什么提升的时候,才开始悔恨自己没有先跑一遍 profiler 。可是如果只是机械地去重复“找出程序热点”、“优化热点”的步骤的话,实际上并没有掌握优化的真谛。 例如下面是我用 Valgrind [...]

pymmseg-cpp: rmmseg-cpp with Python interface

以前为了提高 RMMSeg 的性能,我写了 rmmseg-cpp ,根据 JavaEye 一段时间的使用情况来看,似乎挺稳定的,性能也很不错。其实 rmmseg-cpp 虽然名字里面有一个 “r” 字,但是算法核心完全是用 C++ 做的,最后才加了一层 Ruby 的接口包装。正巧最近我又两个用 Python 的项目都要用到中文分词,便决定给 rmmseg-cpp 加一个 Python 的接口。 正如我在 On the Rubinius FFI 一文中描述的一样,做到 Native 模块的接口有两种方法,一种是我在 rmmseg-cpp 中用的写 C 代码来粘合二者。另一种则是直接用语言提供的 [...]

Notes: How to make a patch

虽然现在各种版本控制工具大行其道,但是有时候还是需要使用相对原始一些的办法提交补丁,制作补丁其实很简单,用 diff 命令,加上 -u 参数生成带有上下文的 unified 格式的 diff 文件,就是一个 patch 了。可是最容易忘记的地方就是后面的参数是先写未修改过的版本呢还是先写修改过的版本。我自己每次都记不住,要去查 man page 。正好今天收到一个 patch ,发现里面的修改都是反过来的,大概也是参数写反了吧。 ^_^ 所以我终于决定把正确的用法记下来: diff -u original new > original.patch [...]

the compiler for skime — from bottom up

最近有空的时候也都在折腾 skime 的 VM ,虽然主要集中在 VM 上,但是写测试代码十分麻烦,每次添加一些辅助功能,最后猛然发现一个编译器的原型已经完成了。我仍然在尝试这种编程方式——并非一开始就把所有的东西都设计好,而是对一些简单的 case ,采用最简单的方法构建出一个可以运行的原型,再通过原型进行扩充。到目前为止似乎都感觉挺好的,因为许多东西都是万事开头难,有了一个大致框架之后剩下的事情就要简单多了,而且原型作为一个快速的可行性尝试也是很不错的。 在刚做出一个 VM 样子的时候,要测试必须手工写字节码,全是数字,写起来非常麻烦,而且一开始指令集也时常有改动,指令的 opcode [...]

MSTC Staff 的睡眠趋势

大约是从去年寒假的时候开始,我就经常在 cc98 的 MSTC 版上发“晚安帖”,就是每天晚上睡觉的时候发一个帖子说一声晚安,后来版面上时常出现一大堆晚安帖的情况,遭到大家的抗议。 :p 后来只好集中到了一个帖子里面,养成了习惯大家也都时常来说晚安。 不管是早有预谋还是心血来潮,我对这个晚安贴的内容分析了一下,得到了类似于下面的结果: 其中横坐标是日期,纵坐标是睡觉时间,由于大家都睡得比较晚,所以把第二天凌晨的时间也记作当天晚上(如 25:00 就是第二天凌晨 1:00 [...]

Introduction to direct threading, or computed goto

现在许多语言都是先把源代码编译成跨平台的字节码,然后通过解释字节码(或是对字节码进行 JIT)的方式执行程序。这比直接遍历 AST 的方式要高效许多。而现在许多虚拟机的字节码其实已经不是以字节 (byte) 为单位,而是以机器字 (word) 为单位(比如 Rubinius 和 Ruby 1.9 的虚拟机 YARV 都是如此),只是仍然沿用“字节码”这一称呼而已,这个原因我稍后会讲。 除此之外,虚拟机一般会分为两种:基于栈和基于寄存器的。虽然在现实的 CPU 上基于寄存器是理所当然的,但是在实现虚拟机的时候却不一样,基于栈的指令集能够让字节码跟紧凑,这样也可以提高 Cache [...]

Rubyforge support git now

不知道是不是我火星了,今天去 Rubyforge 注册 rmmseg-cpp 项目的时候发现在 SCM 那里可以选 git 了。不知道是什么时候加上的支持,这下应该会方便许多了。不过刚注册的项目还没有通过审核,到时候立即试用一下,这样在 github 和 Rubyforge 同时有一个 repo 应该也是能很方便地同步的了! :)

rmmseg-cpp: rmmseg in C++

RMMSeg is an implementation of MMSEG Chinese word segmentation algorithm. It features full integration with Ferret. The original version is written in pure-Ruby, which includes two algorithms: Complex Algorithm: Maximum matching with three-word chunk filtering. The accuracy is good. But the [...]

Google Summer of Code 2008: First Chapter

Finally, I was accepted by Thousand Parsec and will work on Schemepy with Timothy Robert Ansell this summer. I hope this would be an enjoyable summer. :) It's been a fairly long time since the announcement of Google Summer of Code 2008. I'll try to write something about that period. I learned a lot [...]

“软件工程”课告一段落

“软件工程”也是计算机专业的必修课之一。我一向对诸如敏捷开发、极限编程之类的东西比较感兴趣,“拥抱变化”给我的印象非常深刻,所以我意识里也有些抵制传统的软件工程。我觉得,对于小的项目来说,花那么多的时间在繁琐的软件工程流程上简直就是浪费;而对于大的项目来说,不管你花多少时间来做计划都是徒劳,因为需求总是会变化,我们要做的只能是“拥抱变化”而不是永远停滞在设计阶段。 但是我想既然这个课是由 CYJJ 来上,应该至少不会无聊到哪里去吧。二十多章的内容被压缩在了 8 周的短学期中,上课又是一百多号人的班级,唯一能吸引人的就是课件里穿插的各种故事(或者说叫做 IT [...]

Use git-svn to fork a project and keep tracking of it

The case is that sometimes you want to add some cool feature to an open source project. But you don't have commit rights to that project. So you checked out a copy of the code and do some local hacking. The problem is that you'll have to track the updates of the original code and merge the changes [...]

内存泄漏分析工具的尴尬

Ruby 内置了 ObjectSpace 可以用来分析当前生存的对象,但是这样的方法有时候并不好用,而且使用 ObjectSpace 会影响到它自己。Evan Weaver 做的 BleakHouse 工具则用 C 直接分析 Heap (以前的版本也是使用 ObjectSpace),可以得到更精确的结果,可以用于内存泄漏的检测。 不过它的文档比较简略, Rails 好像可以直接用,而非 Rails 程序则只要“构建一个 BleakHouse::Logger 对象,并在合适的时候调用其 snapshot 方法”。我不是很清楚什么是“合适的时候”,我尝试在每一轮调用主要执行代码的时候调用一次 [...]

[ANN] RMMSeg 0.1.2 Released

RMMSeg 发布了 0.1.2 版,主要是对性能进行了一些改进,以下是引用 RubyForge 上的通告:

Concurrency vs Parallelism

一直对 Concurrency 的理解不是很清楚,很多相关的概念也就搞不清楚了。依稀地记得在哪里看到“并发(Concurrency)”和“并行(Parallelism)”并不是同一个概念,今天搜索了一下,发现果然是这样的。 如果对多个进程来讲,并行就是指他们真正意义上地同时执行,这只有在多核的机器上或者是在分布式的环境下才能实现。而并发则更宽泛一些,并发的进程可能是并行的,也可能不是。简单地说,如果有两个进程 P1 和 P2 是并发的,那么会有如下的一些可能的情况: P1 先于 P2 执行。 P2 先于 P1 执行。 P1 和 P2 同时执行(Parallelism)。 P1 和 P2 [...]

[ANN]RMMSeg 0.0.1 Released

RMMSeg 是 MMSEG 中文分词算法的 Ruby 实现。可以作为独立的程序运行,也可以方便地和 Ferret 进行集成。 今天凌晨在完成了与 Ferret 的集成工作以后,我发布了 0.0.1 版,可以从 RubyForge 进行下载,也可以直接使用 RubyGems 进行安装: $ sudo gem install rmmseg 下面是引用 RubyForge 上的 Announcement :

RMMSeg: Ruby 实现中文分词

我在前面曾经提到过,中文分词比较困难,不像英文那样,直接在空格和标点符号的地方断开就可以了。 Jack 在评论中提到即使是英文,在进行短语层次的分“词”时也会有类似的困难。还有在进行手写识别时,空格有时候不能很精确地识别出来,也会要用到中文分词中的一些技术。 RMMSeg 我近日做的一个 Ruby 的中文分词实现,下一步是和 Ferret 进行集成。不过,在介绍 RMMSeg 之前让我先来简要介绍一下中文分词。 如何分词? 那么中文分词究竟要如何做呢?想想你自己看到一个句子的时候,如何进行分词?似乎是及其复杂的吧?好像感觉到现在的电脑还达不到这个层次,至少一台普通 PC [...]

Ruby: 提升性能的几点尝试

近日做一个 Ruby 的程序需要用到一个大约 2 MB 大小的词典,我把它构造在一个 Ruby 的 Hash 里,然而程序启动需要花上大约 4 秒多的时间,主要都是花在加载词典上了。虽然这个程序许多情况下可以在初始化之后处理许多数据,因此可以把启动时间忽略掉,但是在测试的时候还是让人相当不爽。于是就想看看是否可以改进。 首先我测试了只读入一个大约 2 M 的文件的操作,速度非常快,在我这里大约在 0.16 秒左右,然后尝试在读入每行的时候把数据加入到一个 Hash 中去,速度降低到了越 0.43 秒左右: h = Hash.new File.open("words.dic", "r") do [...]

Handling UTF-8 in Ruby

Ruby 1.9.0 已经发布了,1.9 的一个重大改进就是对 Unicode 的支持,这里有一篇介绍 Ruby 1.9 中 Unicode 的文章,可惜是日文的,不过配合代码和部分汉字应该能理解大概意思。 在 Ruby 1.9 中,将如下代码保存为 UTF-8 编码,可以轻松运行通过: # -*- coding: utf-8 -*- require 'test/unit' class TestUnicode 注意第一行的注释中的 coding: utf-8 是必须的(当然也可以通过其他各种方式来指定,不过我很喜欢这种方式,因为这样 Emacs 也可以认出这个文件的编码来)。在 Ruby [...]

Automate interaction with websites using Mechanize

Mechanize 是一个用于在 Ruby 脚本里将与 Web 页面的交互工作自动化的库。它会自动处理 Cookie 、重定向、Referer 之类的东西,使用起来非常方便。我就用我今天写的一个小脚本作为例子来介绍一下 Mechanize 吧! 其实我是在寻找 Ruby 里面处理 Cookie 的库的时候找到它的。学校的网络以前是要先通过一个 Web 页面登录才能上网的(可恶的电信!),早就有前辈们写了上网登录脚本,方便使用(事实上在 Linux 下想要使用学校提供的 201+ 卡方式访问校外网的话,只有用登陆脚本了,电信提供的 IE 插件根本没法用)。可是脚本是用 perl [...]

当有虚拟机在运行的时候阻止 Windows 关机

我经常在后台开一个虚拟机运行 Linux ,而几乎每次关机的时候都忘记了还有一个虚拟机在运行,导致 Linux 非正常关机了。所以我写了一个小程序来防止这种悲剧继续发生:在关机的时候检测是否有虚拟机在运行,有则阻止 Windows 关机。 广告时间 在介绍我的小程序之前,我实在是忍不住要对我现在用的虚拟机和虚拟桌面广告一番了! :p VirtualBox 是一个很不错的虚拟机。和老牌的 VMware 对比,也有许多优点: VirtualBox 可以免费使用,而且还有一个开源版本。而 VMware 是商业软件,虽然 VMware Player [...]

Write a Scheme Interpreter in Ruby(2): THE Interpreter

在上一篇文章中我们实现了对 scheme 代码的 parse 和 analyze 过程,并得到了一些可以直接 eval 的对象(String ,Symbol ,Number 和 Cons ),可是光凭这些并不足以让我们的解释器跑起来。这次我们要添加必要的代码,实现一个真正可运行的解释器。 在前面的代码中,我们已经实现了 scheme 中的几个基本对象的求值:作为 atom 的 String 、Symbol 和 Number 以及作为 list 的 Cons 都已具体实现了 eval 方法。事实上 atom 的求值已经不需要加什么其他代码了,但是 Cons 类却是耍了一个把戏,仔细看 Cons [...]

Write a Scheme Interpreter in Ruby(1): Parser & Analyser

也算是突然心血来潮吧,就想写一个 Scheme 的解释器,其实也是心血来潮了许多次了,只是一直都只是一个想法,最主要的原因还是因为自己对编译原理一无所知吧,也许明年上过编译原理课之后就好写了。不过这次真是心血来潮了,拦都拦不住,怕是等不到明年了。 不管写得出来写不出来,也都先试试吧!多次见石老师演示过 boost::spirit ,计算理论课上也学过了上下文无关文法,似乎还是知道个大概。于是我就开始找 Ruby 的 parser 库。 好像 parser 也有许多种,什么 Recursive Descent [...]

单元测试的绿条条

其实自己对单元测试那套东西也是听说过不少的,而且自己也觉得挺有道理,却是嘛,如果有测试结果摆在那里的话,重构起来胆子都会更壮!不过我却大多数时候都是在提心吊胆地写代码,虽然项目已经分成了几个小的模块,但是当用到其他模块的功能时却老是担心会有错误,而且却是经常会有 bug 散布在各个模块中。 我明白单元测试的重要性,可是却总是“没有时间”(或者所用的工具不太合适)去写单元测试。直到最近有了亲身体验,我才明白:我以前根本没有明白单元测试的重要性!

Memory Barrier

今天在 freecity 的 DistributedSys 版看到在讨论 memory consistency 的问题,潜水的时候看到 shifan 给的两篇文章,其中一篇 barrier 中有一个例子,就是在没有 barrier 的情况下顺序乱掉了,对这个东西一直一知半解,所以也决定实践一把,就照着类似地写了一个程序: #include #include #define ITERATIONS 500000000 typedef volatile unsigned int T; T var1 = 0; DWORD WINAPI writer(T *pvar2) { while (1) { [...]

回忆录:KDB

接着上一篇回忆录,KDB 也是一个 MiniSQL 了,这是在大一下的时候,由于时间间隔不是很久,总结了许多问题,重写了所有的源代码,我给它取了一个名字,知道 KDB 的名字由何而来吗?看这个幻灯片里面的片段,应该就能猜到了吧。

回忆录:MiniSQL

在上一篇 Blog 中列举了几次 MiniSQL 开发总结的一些经验教训吧,在整理那些东西的时候也翻出许多有趣的东西来,也来回忆回忆,哈哈!MiniSQL 确实是个十足的 MiniSQL ,因为我们在着手写数据库的时候甚至都还不知道数据库该怎么用,大概了解了一下 select 之类的东西,但对 join 之类的却是完全没有概念,于是我们的数据库里面自然也不支持 join 操作了,简而言之就是一个普通的有索引的表。而且我们为表的每一个 attribute 都建立了索引。当时的分工是我做数据库内容和索引的管理,moonykily 做用户交互和 SQL 解析,我做的部分如下图所示:

KDB2 开发小结

最近消失了好久,主要是考试吧,大三课程不多,但是都是学得累得很的那种。还有就是课程 Project ,最近这个就是很著名的 MiniSQL 了,经常都听学长们说,做一个 MiniSQL 下来确实会收获很多的。本来也是要认真做的,但是时间估计失误,在 6 号的时候才得知是 11 号截止,所以最后有些仓促了,不过最后还是做完了,已知的 Bug 都修正并且通过了压力测试,心里面也是很高兴的。这里写下一点总结吧,一是给大家分享一下,也是留给自己将来看的,我的 Blog 专门有一个分类就是 Bug Archive ,我主要就是想把自己平时实际开发中犯的错误和遇到的 Bug [...]

More about Greasemonkey: Sandbox

我在上一篇 Blog 中简单地介绍了 Greasemonkey 。并推荐了 Dive into Greasemonkey 这个教程。这次我要介绍的是 Greasemonkey 的沙盒。其实我见过一个朋友在这上面碰过钉子,我自己也正好碰到了问题,便去 GM 的 wiki 上查找了相关的资料。这里把我知道的共享出来,免得有朋友再走弯路,因为 Dive into Greasemonkey 里面的一个例子也是无法正确执行的,也许是教程有些旧了的缘故吧,GM 沙盒也是在不断完善的。

Introduction to Greasemonkey

Greasemonkey 是 Firefox 的一个扩展,它能让你通过自定义的脚本来修改你所访问的网页的行为。Greasemonkey 建立起一个平台,用户通过编写在这个平台上运行的“用户脚本(user scripts)”来修改网页的行为。为什么要修改网页的行为呢?这其实跟为程序打热补丁差不多,比如程序有 Bug ,你想修改程序的行为,你想添加或者去掉某个功能,这些都是会经常碰到的情况。举几个实际的例子: 让百度 MP3 搜索直接显示出下载链接的用户脚本。 去掉 Gmail 的编辑页面右边的广告让编辑框更宽一些的用户脚本。 修复本科生选课网(ZJU)的下拉菜单在 [...]

Aspect-Oriented Programming

昨天的 POM 和大家一起讨论了下 AOP 这个东西,这个东西从年龄上来说应该是不小了,不过目前应用似乎还并不广泛吧,大家了解也并不多,所以我作为话题发起者还是事先收集了一点资料,做一个 Slide : 其实虽然没有专门地用像 AspectJ 这样的东西去做 AOP ,但是 AOP 这种思想其实应该是被接受得比较广泛了,特别是那些相对比较动态的语言里面,做起来也轻松许多,而像 Rails 以及 Spring 这些流行的框架里面都可以见到 AOP 的影子。AOP 将来将会如何发展呢?我也不敢妄下猜测,只有拭目以待了。 :)   这里是 Slide 下载 AOP.pdf。

Small Mem Alloc: The Loki Way

在 Modern C++ Design 一书中有 Loki 库中用于小对象内存分配方法的详细介绍,不过书中用的 Loki 库的版本和我下到的版本应该不一样(我下载到的是 0.1.6 版),所以中间有一些细微的差别,不过总体上是一样的。 整体架构是这样:最上层是 SmallObject 和 SmallValueObject ,分别用于多态和 POD 情况下的小对象的基类,只要继承自他们就可以拥有小对象内存分配的特殊的 new 和 delete 函数。这两个类的区别就是是否有 virtual 的析构函数。如果是 POD 则不需要虚拟西沟函数,并且 SmallValueObject [...]

Small Mem Alloc: The SGI-STL way

最初接触 C 语言的时候就对它 malloc 的内存管理感到奇怪,那么多 malloc 和 free 调用,申请内存的大小也没有什么规律,怎么能高效地管理呢?后来大概了解了下,感觉似乎产生碎片之类的情况是不可避免的,要不如果让算法太过复杂的话,调用一次 malloc 的成本也又太高了,这样反而让我平时写程序的时候调用 malloc 都显得有些心有余悸。 不过事情始终是不可避免的,为了少产生碎片,C 程序员们都倾向于一次申请大块的内存吧。但是到了 C++ 里面情况又变了,有许多小对象(诸如智能指针或者 Functor 一类的对象)如果在 heap [...]

多多益善的原则

最近在看《Interaction Design -- Beyond Human-Computer Interaction》一书的时候看到里面一处说起了人们“多多益善”的心理。一些有趣的行为,自己也经常那样去干,仔细去想就能发现那样的行为其实很傻,只是却被当做“理所当然”的行为而从来没有去想过罢了。 例如在杭州大热天里蒸了一天,终于回到室内,赶紧打开空调,如果你理想的温度是 22 度,你是会直接开到 22 [...]

Does Visual Studio Rot the Mind?

...there’s still coding to do, but there’s no APIs, there’s no classes, there’s no properties, there’s no forms, there’s no controls, there’s no event handlers, and there’s definitely no Visual Studio. It’s just me and the code, and for awhile, I feel like a real programmer again. [...]

Workflows of SCM

版本控制的概念从最初的手工加版本号(比如,为旧的文件加上 .orig 后缀)以及 RCS 开始,主要体现于各自本地进行版本控制。到后来 CVS 模式流行起来,出现了中央仓库的概念。而今天大行其道的分布式版本控制系统,似乎又把主角带回了各自的本地主机那里。然而于以往各自独立的主机不一样,作为各个分布式节点的主机,在相互独立的同时,又互相有紧密的联系,甚至会出现一个特别重要的节点,充当一个“伪中央仓库”的角色。 我在 Git and Subversion 这篇 Blog 里面曾经比较过 Git 和 Subversion [...]

动态语言的尴尬

一提到动态语言,一般都会想到像 Python、Perl 以及 Ruby 之类的语言了,按照 Wikipedia 上的定义,动态语言是这样的: Dynamic programming language is a term used broadly in computer science to describe a class of high level programming languages that execute at runtime many common behaviors that other languages might perform during compilation, [...]

我以前的笔记

以前用 Emacs Muse 写了不少的笔记,自己觉得有些东西还是挺有用的,至少我自己也经常回去查阅,有些东西不记下来过一段时间还真忘记了。只是一直没有合适的地方挂出来给大家分享。虽然现在已经很少再添加新的东西了,不过既然有这个机会,我还是挂出来,免得白白写了些东西,只有我自己看到了。 :) 我把它放在了这里: http://pluskid.lifegoo.com/wiki/index.html

git and subversion

Linus 在 Google 做了他对于版本控制软件的演讲。他似乎非常偏爱分布式版本控制软件,否则宁愿用 tarball+patch (其时 tarball+patch 确确实实是一种分布式的方法呢!)。以至于在 Linux 内核不能试用 BitKeeper 以后,他自己动手写了 git 。他对版本控制软件有许多要求,比如: 取出来的东西要和放进去的东西一样。如果连数据的完整性都无法保证的话,谁还敢用这样的版本控制软件?不过确实有这样的软件存在呢。 分布式。我在后面会解释分布式的好处。 高效率。Linux 内核也算是一个很大的软件了,如果版本控制系统运行起来慢吞吞的,确实是非常让人恼火的呢。 [...]