概述:最近经常听别人的面试题目是读取一个大文件,然后出来读取到的字符串,比如某串的个数了,某串的出现频率之类的,和朋友聊天过程中决定用不同的语言比个赛,分别是c,python,shell。我原本以为c语言一定会获胜(毕竟以效率著称),但结果却是python完胜而且是数量级上的完胜,正当我感叹python大法好时。。。
题目: 现给一个文件400M(该文件是由/etc/passwd生成的),统计其中root字符串出现的次数。
一.c语言实现版
#include <stdio.h>
#include <time.h>
int main(){
int cnt=0;
int start,end;
FILE *fp;
char a[4]="oot";
char b[4];
start = time((time_t*)NULL);
fp = fopen("/root/bigtest", "r");
while(!feof(fp)){
while(!feof(fp)&&fgetc(fp)!='r');
// if (feof(fp)){
// break;
// }
if(fgetc(fp)=='o'){
if(fgetc(fp)=='o'){
if(fgetc(fp)=='t'){
++cnt;
}
}
}else{
continue;
}
//printf("%s----------\n",b);
}
end = time((time_t*)NULL);
printf("%.2fs %ld\n",((end-start)*1.0),cnt);
fclose(fp);
return 0;
}
c语言版就是直接从文件中一个字符一个读取,然后判断,最终输出时间。我们看下用时。
[root@foundation3 Desktop]# gcc 1.c -o big
[root@foundation3 Desktop]# ./big
6.00s 745540
用了6s时间,计算出有745540个root
二.shell版本
使用shell的好处就是简洁,但是速度就不敢恭维了
#!/bin/bash
starttime=`date +'%s'`
cat /root/bigtest | grep -o root |wc -l
endtime=`date +'%s'`
echo $((endtime-starttime))
[root@foundation3 Desktop]# bash big_shell.sh
745540
12
用12s,计算出745540个root
三.python版本
通过python的上下文管理器打开文件,在使用内建的count函数计算每行的root个数,代码简洁程度一点都不比shell差。
# /usr/bin/env python
import time
sum=0
start=time.time()
with open('/root/bigtest') as f:
for i in f:
new=i.count('root')
sum+=new
print sum,time.time()-start
[root@foundation3 Desktop]# python /root/bigpy.py
745540 0.781894922256
这个时间让我震惊简直,比c快了将近10倍好不好。
为了探究他读文件的机制我试了很多方法,一开始以为他是运用了pytho的多线程,就写了如下的代码
import threading,time
start=time.time()
sum=0
def count(text):
global sum
sum+=text.count('root')
# print 'thread end'
f=open('/root/bigtest')
while True:
text=f.read(1000000)
t=threading.Thread(target=count,args=(text,))
# print 'thread begin'
t.start()
if text == '':
break
t.join()
print 'thread is ended \ntime is %s num is %s' %(time.time()-start,sum)
[root@foundation3 Desktop]# python multibit.py
thread is ended
time is 0.72488617897 num is 745538
多线程版本好像并没有多少提升,但是计算的好像有点问题,应该是切片的时候正好切到了root,导致计算出错。比正常计算的少了两个。
四.python的复制的原理
其实这个发现是一个巧合,大家有没有发现,我是先运行了其他版本的读取程序,最后才运行的python版本的程序。问题就出在这里,刚才我重启了次电脑,优先运行了一下python的程序,我发现速度变慢了。如下:
[root@foundation3 Desktop]# python /root/bigpy.py
745540 6.27875995636
用了6s多,明显和以前的不一样啊,难道程序被改了,我又运行一遍,发现又是零点几秒了,我恍然大悟,一定是cache的原因。
现在我们清一下cahce
[root@foundation3 Desktop]# echo 3 > /proc/sys/vm/drop_caches
[root@foundation3 Desktop]# echo 3 > /proc/sys/vm/drop_caches
[root@foundation3 Desktop]# free -m
total used free shared buff/cache available
Mem: 3590 1117 2149 163 323 2131
Swap: 3839 0 3839
现在的cache是323。
然后执行一次python的脚本,先是发现了读取时间又变成了7s多,可以确定是cache的缘故。现在再看一下cache。
[root@foundation3 Desktop]# free -m
total used free shared buff/cache available
Mem: 3590 1117 1741 163 731 2101
Swap: 3839 0 3839
[root@foundation3 Desktop]#
cache明显增加了。证明了我们的猜想,python是会读取cache中的数据,所以会比其他的快很多。