2011-07-19 85 views
13

我有許多浮點數形式的數據文本文件。我正在尋找用C++讀取它們的最快方法。如果這是最快的,我可以將文件更改爲二進制文件。讀取輸入文件,最快的方式可能嗎?

如果您可以給我提示或轉介給我一個完整解釋的網站,那將是非常好的。我不知道是否有任何圖書館能夠快速完成這項工作。即使有任何開源軟件能夠完成這項工作,那也是有幫助的。

+2

請不要將C++問題標記爲'c'。這只是煩人的。 –

回答

24

擁有二進制文件是最快的選擇。不僅可以直接在單個操作(非常快)中以原始istream::read的陣列讀取它,但是如果操作系統支持它,甚至可以將文件映射到內存中;您可以在Windows上使用open/mmap,在Windows上使用CreateFile/CreateFileMapping/MapViewOfFile,甚至可以使用Boost跨平臺解決方案(感謝@Cory Nelson指出)。

快速&骯髒的例子,假設該文件包含了一些float S的原始表示:

「正常」 改爲:

#include <fstream> 
#include <vector> 

// ... 

// Open the stream 
std::ifstream is("input.dat"); 
// Determine the file length 
is.seekg(0, std:ios_base::end); 
std::size_t size=is.tellg(); 
is.seekg(0, std::ios_base::beg); 
// Create a vector to store the data 
std::vector<float> v(size/sizeof(float)); 
// Load the data 
is.read((char*) &v[0], size); 
// Close the file 
is.close(); 

共享內存:

#include <boost/interprocess/file_mapping.hpp> 
#include <boost/interprocess/mapped_region.hpp> 

using boost::interprocess; 

// .... 

// Create the file mapping 
file_mapping fm("input.dat", read_only); 
// Map the file in memory 
mapped_region region(fm, read_only); 
// Get the address where the file has been mapped 
float * addr = (float *)region.get_address(); 
std::size_t elements = region.get_size()/sizeof(float); 
+5

[Boost Interprocess](http://www.boost.org/doc/libs/1_47_0/doc/html/interprocess/sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file)提供了跨平臺的內存映射文件。 –

+0

@Cory:呃,不錯,不知道Boost也得到了。 –

+0

如果文件已被緩存,內存映射將會非常快。如果不是,'read'將會勝過它。 –

5

你瓶頸在I/O中。您希望程序以最少的I/O調用將盡可能多的數據讀入內存。例如,讀取一個fread的256個數字比一個數字的256個fread快。

如果可以,請格式化數據文件以匹配目標平臺的內部浮點表示法,或至少與您的程序表示法相匹配。這減少了將文本表示轉換爲內部表示的開銷。

如果可能的話,繞過操作系統並使用DMA控制器讀取文件數據。 DMA芯片承擔了將數據從處理器的肩上讀取到內存中的負擔。

壓縮你的數據文件。數據文件想要位於磁盤上的一組連續的扇區中。這將減少花在尋找物理盤片上不同區域的時間。

您是否編程需求對磁盤資源和處理器的獨佔控制權。阻止所有其他不重要的任務;提高程序執行的優先級。

使用多個緩衝區來保持磁盤驅動器旋轉。花費大量時間等待硬盤加速和減速。您的程序可以處理數據,而其他數據則將數據存儲到緩衝區,從而導致...

多線程。創建一個線程來讀取數據,並在緩衝區不爲空時提醒處理任務。

這些應該讓你忙一會兒。所有其他優化將導致性能收益微不足道。 (如直接訪問硬盤驅動器控制器,將其轉移到您的緩衝區中。)

+0

有趣..... – tomasz

+1

OP有一個文本文件。加速#2,將該文本文件轉換爲二進制文件,將極大地加快速度。按照#1的方式,儘可能多地讀一遍。之後的一切都是肉汁。 –

2

另一個注意編譯模式。 我試着用1M行解析一個文件。調試模式消耗50secs來解析數據並附加到我的容器。釋放模式消耗的速度至少快十倍,大約4秒。 下面的代碼是在使用istringstream將數據解析爲2D點(,)之前讀取整個文件。

vector <float> in_data; 
string raw_data; 

ifstream ifs; 
ifs.open(_file_in.c_str(), ios::binary); 
ifs.seekg(0, ios::end); 
long length = ifs.tellg(); 
ifs.seekg(0, ios::beg); 
char * buffer; 
buffer = new char[length]; 
ifs.read(buffer, length); 
raw_data = buffer; 
ifs.close(); 
delete[]buffer; 
cout << "Size: " << raw_data.length()/1024/1024.0 << "Mb" << endl; 
istringstream _sstr(raw_data); 
string _line; 

while (getline(_sstr, _line)){ 
    istringstream _ss(_line); 
    vector <float> record; 
    //maybe using boost/Tokenizer is a good idea ... 
    while (_ss) 
    { 
     string s; 
     if (!getline(_ss, s, ',')) break; 
     record.push_back(atof(s.c_str())); 
    } 
    in_data.push_back(record[0]); 
}