2008年12月23日星期二

2008年12月21日星期日

Performance comparison 性能比较 : Java vs python vs c vs c++

哈哈,标题很大,内容很弱。
今天无聊,做了个小实验。假设我们有个任务,输入是一个文本文件,每行两个整数用空格分开,输出是一个文本文件,每行是输入对应行的和。这个例子虽小,但确是比较经典的场景。我用java, c, c++, python写了好几个程序,每个都在接近日常编码的情况下尽量写的快一点,看看究竟速度有什么差别。

程序的输入都是一样的,一个文本文件,有10,000,000行,每行两个1000以内的随机整数。机器是Macbook Intel Core Duo 2.0G, 2G内存 DDR667, 5400转seagate磁盘 8M缓存,Mac OS X Leopard 10.5.5. 虽然这些不是重要因素,但还是要介绍一下。

时间测试用的是bash的time命令,取的是real时间。

1) java,用split,java version "1.6.0_07" Java(TM) SE Runtime Environment (build 1.6.0_07-b06-153) Java HotSpot(TM) 64-Bit Server VM (build 1.6.0_07-b06-57, mixed mode)

程序如下

TextFileReader r = new TextFileReader("/Users/sixiance/Desktop/test.txt");
TextFileWriter w = new TextFileWriter("/Users/sixiance/Desktop/test.out.txt");
String l = null;
int a, b;
while ((l = r.readLine()) != null) {
String [] cols = l.split(" ");
a = Integer.parseInt(cols[0]);
b = Integer.parseInt(cols[1]);
w.writeLine(Integer.toString(a + b));
}
r.close();
w.close();

说实话split是很消耗时间的,每次都要生成一个正则表达式Pattern对象。这程序运行四次, 时间均值17.46125
标准差0.3162429,单位都是秒。

这里面的TextFileReader/Writer就是简单包装了一下new BufferedReader(new InputStreamReader(new FileInputStream()))

2) java 不用split, VM同上

既然刚才知道split比较费时间,那我就不用split,用如下的代码片段代替

int pos = l.indexOf(" ");
a = Integer.parseInt(l.substring(0, pos));
b = Integer.parseInt(l.substring(pos+1));

结果比split好很多,均值 10.26375标准差0.133784,快了好多。

3) c, gcc -O3, version 4.0.1 (Apple Inc. build 5465)

c程序如下:

#include "stdio.h"

int main(int argc, char** argv) {
FILE* fp = fopen("/Users/sixiance/Desktop/test.txt", "r");
FILE* ofp = fopen("/Users/sixiance/Desktop/test.cout.txt", "w");
int a, b;
while (!feof(fp)) {
fscanf(fp, "%d %d\n", &a, &b);
fprintf(ofp, "%d\n", a + b);
}
fclose(fp);
fclose(ofp);
}

结果自然是无敌快:均值8.09575, 标准差0.1816670

4) python, Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26) [GCC 4.0.1 (Apple Inc. build 5465)] on darwin

代码如下

f = open("/Users/sixiance/Desktop/test.txt", "r")
of = open("/Users/sixiance/Desktop/test.pyout.txt", "w")
for line in f:
[a,b] = line.strip("\n").split()
of.write(str(int(a) + int(b)) + "\n")
f.close()
of.close()

这个也是用了split,速度是很慢的, 均值48.5335, 标准差0.2030706

5) c++, g++ -O3, gcc version 4.0.1 (Apple Inc. build 5465)

程序如下

#include
#include

using namespace std;

int main(int argc, char** argv) {
ifstream ins("/Users/sixiance/Desktop/test.txt");
ofstream outs("/Users/sixiance/Desktop/test.cppout.txt");
int a, b;
while(!ins.eof()) {
ins >> a >> b;
outs << (a+b) << endl;
}
ins.close();
outs.close();
}

都用c++的方法,不是用c的部分。这个惊人的慢:均值68.3783,标准差0.3763082。c++ stream真不是盖的,敬仰啊... 这个的sys时间花的比user还多,而且都比c和java慢了好多。

6) c++ 不用endl
思考一下,罪魁祸首是endl,每个endl都会导致stream flush(这其实挺sb的)。把endl改成"\n",均值14.734,标准差0.2281447,这次是比较正常了。

总结回顾

让我们回顾一下,把各种情况下的时间都画在一个图里面:



这些数字绝不是要说明那个语言好或是那个语言快(本身意义也不大),因为实际的问题千差万别,很难用这么小的例子来概括。但是这些数字确实可以告诉我们,在抄起家伙随心地写一些小工具和小实验程序时候,大概会有一个什么性能差距。

2008年12月14日星期日

恢复游泳

今天晚上回到久违的学校游泳馆,开始恢复游泳了。

周四按摩的时候,按摩师傅说你们这些每天坐在电脑前面的人脊椎都不太好,得经常锻炼一下。我觉得这个挺重要,好几个兄弟颈椎都已经出状况了,赶紧就问啥锻炼最好。师傅介绍了几种方法,最好的还是游泳,看来经常游游是百利而无一害啊,不错不错。

游泳馆在奥运前半年的时候就封馆支援运动员训练了,上一张游泳卡就白搭了100多在里面。今天重回游泳馆,发现奥运还是有好处的,原来走廊里面剥落的墙皮现在变成瓷砖了,隔不远还有小装饰画,感觉好很多。更衣室里也重新装修,洗澡换成了感应喷头,热水也是哇哇地好,谁说奥运没啥好处,哈哈。

今天先游了1300米热热身,争取这次在游泳卡过期之前都把它用掉~

2008年12月8日星期一

魔方,无敌魔方

办公室有一个魔方,最普通的3x3那种,我搞了半天才搞定两个面,实在是太弱智了。

共享两个视频,第一个是机器人的,第二个是活人的






叹为观止啊

2008年12月7日星期日

美国的神奇之楼,竟然倒在一起




在google maps上偶尔看到的,应该是拼接的结果,但这拼接的也太好了

2008年12月1日星期一

校园风光



发两个校园随拍,安静的冬日午后。