本文接上一篇文章————探寻C++最快的读取文件的方案
仔细看了一下原文,发布时间是五年前,五年时间,无论是硬件还是软件环境都有了巨大的进步,我决定动手实现一下。
首先编写了一个生成生成随机数的程序,代码如下:
1 2 3 4 5 6 7 8 9 10 11
| #include<cstdio> #include<ctime> #include<cstdlib> int main () { freopen("data.txt","w",stdout); srand(time(0)); for(int i=0;i<1000000;i++) printf("%d ",rand()); return 0; }
|
生成一千万个随机数,并存储在data.txt
中,约54MB。
编写使用scanf
读取数据的程序,代码如下:
1 2 3 4 5 6 7 8 9 10 11
| #include<cstdio> #include<ctime> int a[10000000]; int main () { int start = clock(); freopen("data.txt","r",stdin); for(int i=0;i<10000000;i++) scanf("%d",&a[i]); printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC); }
|
执行之后,使用时间为1.18s
,相比于原文的2.01
秒,缩短了一截,然后测试一下使用cin
输入的情况,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| #include<cstdio> #include<ctime> #include<iostream> int a[10000000]; int main () { int start = clock(); freopen("data.txt","r",stdin); for(int i=0;i<10000000;i++) std::cin>>a[i]; printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC); }
|
cin
的使用时间为4.67s
,比scanf
更长,但是相比于原文的6.38s
还是短得多。
然后取消cin
与stdin
之间的同步之后,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include<cstdio> #include<ctime> #include<iostream> int a[10000000]; int main () { int start = clock(); std::ios::sync_with_stdio(false); freopen("data.txt","r",stdin); for(int i=0;i<1000000;i++) std::cin>>a[i]; printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC); }
|
时间大幅缩短,为1.24s
,与scanf很接近了。
然后按原文测试读入整个文件,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include<iostream> #include<ctime> #include<cstdio> const int MAXN = 10000000; const int MAXS = 60*1024*1024; int numbers[MAXN]; char buf[MAXS]; void analyse(char *buf, int len =MAXS) { int i; numbers[i=0]=0; for(char *p=buf;*p && p-buf<len;p++) if(*p == ' ') numbers[++i]=0; else numbers[i]=numbers[i]*10+*p-'0'; } void fread_analyse() { freopen("data.txt","rb",stdin); int len = fread(buf,1,MAXS,stdin); buf[len]='\0'; analyse(buf,len); } int main () { int start = clock(); fread_analyse(); printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC); return 0; }
|
时间如原文一般,大幅缩短,我这里测试得到0.37s
,使用read
测试,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include<iostream> #include<ctime> #include<cstdio> #include<unistd.h> #include<fcntl.h> const int MAXN = 10000000; const int MAXS = 60*1024*1024; int numbers[MAXN]; char buf[MAXS]; void analyse(char *buf, int len =MAXS) { int i; numbers[i=0]=0; for(char *p=buf;*p && p-buf<len;p++) if(*p == ' ') numbers[++i]=0; else numbers[i]=numbers[i]*10+*p-'0'; } void read_analyse() { int fd = open("data.txt",O_RDONLY); int len = read(fd,buf,MAXS); buf[len]='\0'; analyse(buf,len); } int main () { int start = clock(); read_analyse(); printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC); return 0; }
|
测试时间为0.31s
,有所进步,不过不是非常明显。
调用mmap
,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include<iostream> #include<ctime> #include<cstdio> #include<unistd.h> #include<fcntl.h> #include<sys/mman.h> const int MAXN = 10000000; const int MAXS = 60*1024*1024; int numbers[MAXN]; char buf[MAXS]; void analyse(char *buf, int len =MAXS) { int i; numbers[i=0]=0; for(char *p=buf;*p && p-buf<len;p++) if(*p == ' ') numbers[++i]=0; else numbers[i]=numbers[i]*10+*p-'0'; } void mmap_analyse() { int fd = open("data.txt",O_RDONLY); int len = lseek(fd,0,SEEK_END); char *mbuf = (char *) mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0); analyse(mbuf,len); } int main () { int start = clock(); mmap_analyse(); printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC); return 0; }
|
运行结果才让我大跌眼镜,虽然我没有眼镜
达到0.49s
,与原文不符(原文中使用mmnp
耗时更短,在我的测试中,耗时变长了),可能是代码与原作者的不一样,原作者只给出一部分代码,而测试需要写出完整的代码,可能我写的代码有问题。
以上测试结果在腾讯云上进行,因为原作者当时的硬件条件可能比不上我所使用的环境,我在树莓派 3B和我自己的电脑上测试了一下,所有平台硬件信息如下:
平台/硬件和软件信息 |
Cent OS |
Raspberry |
Windows |
CPU |
1 core |
Broadcom BCM2837 1.2GHz |
intel Core 5200u 2.2GHz |
RAM |
1GB |
1GB |
12GB |
Gcc |
4.8.5 |
4.9.2 |
5.3.0 |
PS: 这里忽略了硬盘的性能,理论上来说,硬盘的性能肯定能影响读写速度,只是没有较好的方法比较三个平台的硬盘性能,只能作罢。 |
|
|
|
测试结果汇总如下: |
|
|
|
方法/平台/耗时(s) |
Cent OS |
Raspberry |
Windows(本机) |
Ubuntu(本机) |
scanf |
1.180 |
14.786 |
4.488 |
1.158 |
cin |
4.670 |
61.255 |
13.026 |
4.309 |
cin取消同步 |
1.240 |
7.694 |
8.086 |
1.135 |
fread |
0.37 |
3.503 |
0.327 |
0.284 |
read |
0.31 |
2.975 |
0.370 |
0.285 |
mmap |
0.49 |
5.945 |
NULL |
0.447 |
生命重在折腾