對於scanf和cin的輸入輸出速度的驗證


本文為https://www.byvoid.com/zhs/blog/fast-readfile的驗證性文章

---------------------------------------------------------------------------

首先生成一千萬個隨機數

 1 #include<cstdio>                       
 2 #include<ctime>                        
 3 #include<cstdlib>                      
 4 int main ()                            
 5 {                                      
 6         freopen("data.txt","w",stdout);
 7         srand(time(0));                
 8         for(int i=0;i<10000000;i++)     
 9                 printf("%d ",rand());  
10         return 0;                      
11 }

我用重定向把數據導出到"data.txt"了。

然后,用scanf來讀取數據,並計時

 1 #include<cstdio>                                               
 2 #include<ctime>
 3 int a[10000000];                                                
 4 int main ()                                                    
 5 {                                                              
 6         int start = clock();                                 
 7         freopen("data.txt","r",stdin);                         
 8         for(int i=0;i<10000000;i++)                             
 9                 scanf("%d",&a[i]);                                
10         printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC);
11 }

執行之后,使用時間為1.18s,相比於原文的2.01秒,縮短了一截,然后測試一下使用cin輸入的情況,代碼如下:

 1 #include<cstdio>
 2 #include<ctime>
 3 #include<iostream>
 4 int a[10000000];
 5 int main ()
 6 {
 7         int start = clock();
 8         freopen("data.txt","r",stdin);
 9         for(int i=0;i<10000000;i++)
10                 std::cin>>a[i];
11         printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC);
12 }

cin的使用時間為4.67s,比scanf更長,但是相比於原文的6.38s還是短得多。
然后取消cinstdin之間的同步之后,代碼如下:

 1 #include<cstdio>
 2 #include<ctime>
 3 #include<iostream>
 4 int a[10000000];
 5 int main ()
 6 {
 7         int start = clock();
 8         std::ios::sync_with_stdio(false);
 9         freopen("data.txt","r",stdin);
10         for(int i=0;i<1000000;i++)
11                 std::cin>>a[i];
12         printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC);
13 }

時間大幅縮短,為1.24s,與scanf很接近了。
然后按原文測試讀入整個文件,代碼如下:

 1 #include<iostream>                                              
 2 #include<ctime>                                                 
 3 #include<cstdio>                                                
 4 const int MAXN = 10000000;                                      
 5 const int MAXS = 60*1024*1024;                                  
 6 int numbers[MAXN];                                              
 7 char buf[MAXS];                                                 
 8                                                                 
 9 void analyse(char *buf, int len =MAXS)                          
10 {                                                               
11         int i;                                                  
12         numbers[i=0]=0;                                         
13         for(char *p=buf;*p && p-buf<len;p++)                    
14         if(*p == ' ')                                           
15                 numbers[++i]=0;                                 
16         else                                                    
17                 numbers[i]=numbers[i]*10+*p-'0';                
18 }                                                               
19                                                                 
20 void fread_analyse()                                            
21 {                                                               
22         freopen("data.txt","rb",stdin);                         
23         int len = fread(buf,1,MAXS,stdin);                      
24         buf[len]='\0';                                          
25         analyse(buf,len);                                       
26 }                                                               
27                                                                 
28 int main ()                                                     
29 {                                                               
30         int start = clock();                                    
31         fread_analyse();                                        
32         printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC); 
33         return 0;                                               
34 }

時間如原文一般,大幅縮短,我這里測試得到0.37s,使用read測試,代碼如下:

#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 #include<iostream>                                                      
 2 #include<ctime>                                                         
 3 #include<cstdio>                                                        
 4 #include<unistd.h>                                                      
 5 #include<fcntl.h>                                                       
 6 #include<sys/mman.h>                                                    
 7 const int MAXN = 10000000;                                              
 8 const int MAXS = 60*1024*1024;                                          
 9 int numbers[MAXN];                                                      
10 char buf[MAXS];                                                         
11                                                                         
12 void analyse(char *buf, int len =MAXS)                                  
13 {                                                                       
14         int i;                                                          
15         numbers[i=0]=0;                                                 
16         for(char *p=buf;*p && p-buf<len;p++)                            
17         if(*p == ' ')                                                   
18                 numbers[++i]=0;                                         
19         else                                                            
20                 numbers[i]=numbers[i]*10+*p-'0';                        
21 }                                                                       
22                                                                         
23 void mmap_analyse()                                                     
24 {                                                                       
25         int fd = open("data.txt",O_RDONLY);                             
26         int len = lseek(fd,0,SEEK_END);                                 
27         char *mbuf = (char *) mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
28         analyse(mbuf,len);                                              
29 }                                                                       
30                                                                         
31 int main ()                                                             
32 {                                                                       
33         int start = clock();                                            
34         mmap_analyse();                                                 
35         printf("%.3lf\n",double(clock()-start)/CLOCKS_PER_SEC);         
36         return 0;                                                       
37 }

達到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: 這里忽略了硬盤的性能,理論上來說,硬盤的性能肯定能影響讀寫速度,只是沒有較好的方法比較三個平台的硬盤性能,只能作罷。不過在下面的表中我對比了我自己電腦上在Windows環境下和Linux環境下的情況。相較於原文,舍去VS的比較信息,全部使用了GNU/GCC.

測試結果如下

方法/平台/耗時(s) Cent OS Raspberry Windows(本機) Ubuntu(本機)
scanf 1.180 14.786 4.488 1.158
cin 13.026 61.255 13.026 4.309
cin(取消同步) 1.240 7.694 8086 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

在同等硬件條件下,Windows比Linux慢得多,在同等環境下,硬件好的自然快,樹莓派充分證明了這一點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM