1. 程式人生 > >探尋C++最快的讀取檔案的方案 C++ IO優化

探尋C++最快的讀取檔案的方案 C++ IO優化

 在競賽中,遇到大資料時,往往讀檔案成了程式執行速度的瓶頸,需要更快的讀取方式。相信幾乎所有的C++學習者都在cin機器緩慢的速度上栽過跟頭,於是從此以後發誓不用cin讀資料。還有人說Pascal的read語句的速度是C/C++中scanf比不上的,C++選手只能乾著急。難道C++真的低Pascal一等嗎?答案是不言而喻的。一個進階的方法是把資料一下子讀進來,然後再轉化字串,這種方法傳說中很不錯,但具體如何從沒試過,因此今天就索性把能想到的所有的讀資料的方式都測試了一邊,結果是驚人的。

競賽中讀資料的情況最多的莫過於讀一大堆整數了,於是我寫了一個程式,生成一千萬個隨機數到data.txt中,一共55MB。然後我寫了個程式主幹計算執行時間,程式碼如下:

#include <ctime>  
int main()  
{  
    int start = clock();  
    //DO SOMETHING  
    printf("%.3lf/n",double(clock()-start)/CLOCKS_PER_SEC);  
}  

最簡單的方法就算寫一個迴圈scanf了,程式碼如下:
const int MAXN = 10000000;  
   
int numbers[MAXN];  
   
void scanf_read()  
{  
    freopen("data.txt","r",stdin);  
    for (int i=0;i<MAXN;i++)  
        scanf("%d",&numbers[i]);  
}   

可是效率如何呢?在我的電腦Linux平臺上測試結果為2.01秒。接下來是cin,程式碼幾乎同上。

出乎我的意料,cin僅僅用了6.38秒,比我想象的要快。cin慢是有原因的,其實預設的時候,cin與stdin總是保持同步的,也就是說這兩種方法可以混用,而不必擔心檔案指標混亂,同時cout和stdout也一樣,兩者混用不會輸出順序錯亂。正因為這個相容性的特性,導致cin有許多額外的開銷,如何禁用這個特性呢?只需一個語句std::ios::sync_with_stdio(false);,這樣就可以取消cin於stdin的同步了。程式如下:

const int MAXN = 10000000;  
   
int numbers[MAXN];  
   
void cin_read_nosync()  
{  
    freopen("data.txt","r",stdin);  
    std::ios::sync_with_stdio(false);  
    for (int i=0;i<MAXN;i++)  
        std::cin >> numbers[i];  
}   

取消同步後效率究竟如何?經測試執行時間銳減到了2.05秒,與scanf效率相差無幾了!有了這個以後可以放心使用cin和cout了。

接下來讓我們測試一下讀入整個檔案再處理的方法,首先要寫一個字串轉化為陣列的函式,程式碼如下

const int MAXS = 60*1024*1024;
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';
} 

把整個檔案讀入一個字串最常用的方法是用fread,程式碼如下:
const int MAXN = 10000000;  
const int MAXS = 60*1024*1024;  
   
int numbers[MAXN];  
char buf[MAXS];  
   
void fread_analyse()  
{  
    freopen("data.txt","rb",stdin);  
    int len = fread(buf,1,MAXS,stdin);  
    buf[len] = '/0';  
    analyse(buf,len);  
}   

上述程式碼有著驚人的效率,經測試讀取這10000000個數只用了0.29秒,效率提高了幾乎10倍!掌握著種方法簡直無敵了,不過,我記得fread是封裝過的read,如果直接使用read,是不是更快呢?程式碼如下:
const int MAXN = 10000000;  
const int MAXS = 60*1024*1024;  
   
int numbers[MAXN];  
char buf[MAXS];  
   
void read_analyse()  
{  
    int fd = open("data.txt",O_RDONLY);  
    int len = read(fd,buf,MAXS);  
    buf[len] = '/0';  
    analyse(buf,len);  
} 

測試發現執行時間仍然是0.29秒,可見read不具備特殊的優勢。到此已經結束了嗎?不,我可以呼叫Linux的底層函式mmap,這個函式的功能是將檔案對映到記憶體,是所有讀檔案方法都要封裝的基礎方法,直接使用mmap會怎樣呢?程式碼如下:
const int MAXN = 10000000;  
const int MAXS = 60*1024*1024;  
   
int numbers[MAXN];  
char buf[MAXS];  
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);  
}   

經測試,執行時間縮短到了0.25秒,效率繼續提高了14%。到此為止我已經沒有更好的方法繼續提高讀檔案的速度了。回頭測一下Pascal的速度如何?結果令人大跌眼鏡,居然運行了2.16秒之多。程式如下:
const  
    MAXN = 10000000;  
var  
    numbers :array[0..MAXN] of longint;  
    i :longint;  
begin  
    assign(input,'data.txt');  
    reset(input);  
    for i:=0 to MAXN do  
        read(numbers[i]);  
end.   

為確保準確性,我又換到Windows平臺上測試了一下。結果如下表:

方法/平臺/時間(秒) Linux gcc Windows mingw Windows VC2008
scanf 2.010 3.704 3.425
cin 6.380 64.003 19.208
cin取消同步 2.050 6.004 19.616
fread 0.290 0.241 0.304
read 0.290 0.398 不支援
mmap 0.250 不支援 不支援
Pascal read 2.160 4.668

從上面可以看出幾個問題

  1. Linux平臺上執行程式普遍比Windows上快。
  2. Windows下VC編譯的程式一般執行比MINGW(MINimal Gcc for Windows)快。
  3. VC對cin取消同步與否不敏感,前後效率相同。反過來MINGW則非常敏感,前後效率相差8倍。
  4. read本是linux系統函式,MINGW可能採用了某種模擬方式,read比fread更慢。
  5. Pascal程式執行速度實在令人不敢恭維。

希望此文能對大家有所啟發,歡迎與我繼續討論。

轉載自:http://blog.csdn.net/shifuwawa/article/details/5811397

相關推薦

【轉載】探尋C++讀取檔案方案

在競賽中,遇到大資料時,往往讀檔案成了程式執行速度的瓶頸,需要更快的讀取方式。相信幾乎所有的C++學習者都在cin機器緩慢的速度上栽過跟頭,於是從此以後發誓不用cin讀資料。還有人說Pascal的read語句的速度是C/C++中scanf比不上的,C++選手只能乾著急。難道C++真的低Pascal一等嗎?

探尋C++讀取檔案方案 C++ IO優化

 在競賽中,遇到大資料時,往往讀檔案成了程式執行速度的瓶頸,需要更快的讀取方式。相信幾乎所有的C++學習者都在cin機器緩慢的速度上栽過跟頭,於是從此以後發誓不用cin讀資料。還有人說Pascal的read語句的速度是C/C++中scanf比不上的,C++選手只能乾著急。難

[Reprint] 探尋C++讀取文件的方案

linu 基礎 作者 con strong input div stdin 瓶頸 作者:BYVoid(https://www.byvoid.com/zhs/blog/fast-readfile) 在競賽中,遇到大數據時,往往讀文件成了程序運行速度的瓶頸,需要更快的讀取

C 按行讀取檔案(但是最後一行會多輸出一行)

#include <stdio.h>   int main()  {      char filename[] = "E:\\data_test\\commands.txt"; //檔名   &nb

2421 Problem C 合併連結串列(線性表)

問題 C: 最快合併連結串列(線性表) 時間限制: 1 Sec  記憶體限制: 128 MB 提交: 72  解決: 57 [提交][狀態][討論版][命題人:外部匯入] 題目描述 知L1、L2分別為兩迴圈單

C/C++ 按行讀取檔案

本文程式碼都在Windows/VC++6.0下測試過, 在linux/g++下也沒有問題。         但是請一定注意linux和Windows檔案格式的區別,比如:    &n

C語言 實現讀取檔案,並統計每個字元出現的個數

/***************** 實現讀取檔案,並統計每個字元出現的個數 *****************/ #include <stdio.h> #include <stdlib.h> unsigned long file_size;

c++ 一次讀取檔案全部內容

讀取一個string std::ifstream in("some.file"); std::string some_str; in >> some_str; 這種方法的問題在於,遇

C# 學習: 讀取檔案流,儲存到位元組中

最近在做檔案資料讀取的測試,C#的檔案讀取,儲存到位元組中,之前對這塊不熟悉,Mark: Stream expectedSteam = new FileStream(path, FileMode.O

c++ std::ifstream 讀取檔案不完整? 是不是忘記了ios_base::binary

一次浪費時間又把你折磨的無以復加的小問題。 讀取圖片本應該讀取20000位元組的,為何只讀取了300位元組?原來少了ios_base::binary!!! 如果讀取的非字串形式的文字,注意應該要加上ios_base::binary,否則可能遇到0就提前返回了EOF。 下面直

Ultimus 的 BPM 方案

Ultimus 最快的 BPM 方案 Ultimus 加快部署與投資回報周期 Ultimus 采用不需程序設計的方法,提供豐富的協同合作能力,以及創新的 Adaptive Discovery 技術來加快部署周期,讓絕

C語言中 .h檔案和.c檔案的區別

要理解.c檔案與.h檔案有什麼不同之處,首先需要弄明白編譯器的工作過程,一般說來編譯器會做以下幾個過程: 1.預處理階段 2.詞法與語法分析階段 3.編譯階段,首先編譯成純彙編語句,再將之彙編成跟CPU相關的二進位制碼,生成各個目標檔案 4.連線階段,將各個目標檔案中的各段程式碼進行絕對地址定位,生成跟特定平

C語言中 .h檔案和.c檔案的區別 (轉)

要理解.c檔案與.h檔案有什麼不同之處,首先需要弄明白編譯器的工作過程,一般說來編譯器會做以下幾個過程:1.預處理階段2.詞法與語法分析階段3.編譯階段,首先編譯成純彙編語句,再將之彙編成跟CPU相關的二進位制碼,生成各個目標檔案4.連線階段,將各個目標檔案中的各段程式碼進行絕對地址定位,生成跟特定平臺相關

hdfs讀取檔案出發java.io.EOFException異常

[2014-05-05 17:42:51] [main] DEBUG - Error making BlockReader. Closing stale NioInetPeer(Socket[addr=/XXXXX,port=50010,localport=55897])  java.io.EOFExcep

C++ 讀取檔案內容到指定型別的變數

#include <iostream> #include <fstream> #include <sstream> #include <string> using namespace std; int main(){ cout <<

C++ 讀取檔案內容到data 結構體 structure

#include <iostream> #include <fstream> #include <stdlib.h> using namespace std; typedef struct { int n; char *data; } BLOCK;

C 讀取文字檔案C 寫文字檔案

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

c++根據檔名讀取.txt檔案

新手程式碼如下: #include<iostream>#include<fstream> #include<string> using namespace std; int main(){ string filename = "";  

CC語言開啟,讀取檔案

文章目錄 C語言開啟,讀取檔案 一、明明白白我的心 二、程式碼飛起來 三、過程不重要,重點看結果 C語言開啟,讀取檔案 一、明明白白我的心   &nbs

C#讀取檔案內容,在指定行插入內容

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; usi