读取输入文件,最快的方式可能

read input files, fastest way possible?

本文关键字:方式可 输入 文件 读取      更新时间:2023-10-16

我有许多浮点数形式的数据文本文件。我正在寻找在c++中阅读它们的最快方法。如果最快的话,我可以把文件变成二进制文件。

如果你能给我提示或给我一个完整的解释网站,那就太好了。我不知道是否有任何图书馆能快速完成这项工作。即使有任何开源软件可以完成这项工作,也会很有帮助。

使用二进制文件是最快的选择。你不仅可以在一个单一的操作中直接在一个原始的istream::read数组中读取它(这是非常快的),而且你甚至可以在内存中映射文件,如果你的操作系统支持它;您可以在POSIX系统上使用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);

瓶颈在I/O。您希望程序以最少的I/O调用将尽可能多的数据读入内存。例如,读取256个带有一个fread的数字比读取256个带有一个fread的数字要快。

如果可以,格式化数据文件以匹配目标平台的内部浮点表示,或者至少是您的程序的表示。这减少了将文本表示转换为内部表示的开销。

绕过操作系统,如果可能的话,使用DMA控制器读取文件数据。DMA芯片减轻了处理器将数据读入内存的负担。

压缩数据文件。数据文件希望位于磁盘上一组连续的扇区中。这将减少在物理盘片上寻找不同区域所花费的时间。

程序要求独占控制磁盘资源和处理器吗?阻止所有其他不重要的任务;提高程序执行的优先级。

使用多个缓冲区来保持磁盘驱动器旋转。大部分时间花在等待硬盘加速和减速上。您的程序可以处理数据,而其他程序将数据存储到缓冲区中,这导致…

多线程。创建一个线程来读取数据,并在缓冲区不为空时通知处理任务。

这些应该能让你忙上一阵子。所有其他优化所带来的性能增益都可以忽略不计。(例如直接访问硬盘驱动器控制器以传输到您的一个缓冲区)

编译模式的另一个注意事项。我试过解析一个有1M行的文件。调试模式花费50秒来解析数据并将其附加到容器中。释放模式消耗至少快10倍,约为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]);
}
相关文章: