用c ++将文件读入内存的最快方法?

时间:2016-11-18 19:12:15

标签: c++ file fstream

我试图以更快的方式读取文件。我目前的做法如下,但对于大文件来说速度非常慢。我想知道是否有更快的方法来做到这一点?我需要存储结构的值,我在下面定义了它。

std::vector<matEntry> matEntries;
inputfileA.open(matrixAfilename.c_str());

// Read from file to continue setting up sparse matrix A
while (!inputfileA.eof()) {
    // Read row, column, and value into vector
    inputfileA >> (int) row; // row
    inputfileA >> (int) col; // col
    inputfileA >> val;       // value

    // Add row, column, and value entry to the matrix
    matEntries.push_back(matEntry());
    matEntries[index].row = row-1;
    matEntries[index].col = col-1;
    matEntries[index].val = val;

    // Increment index
    index++;
}

我的结构:

struct matEntry {
    int row;
    int col;
    float val;
};

文件的格式如下(int,int,float):

1 2 7.9
4 5 9.008
6 3 7.89
10 4 10.21

更多信息:

  • 我知道运行时文件中的行数。
  • 我正面临一个瓶颈。分析器说while()循环是瓶颈。

3 个答案:

答案 0 :(得分:3)

为了简化操作,我为您的结构定义了一个输入流操作符。

std::istream& operator>>(std::istream& is, matEntry& e)
{
    is >> e.row >> e.col >> e.val;
    e.row -= 1;
    e.col -= 1;

    return is;
}

关于速度,如果没有very basic级别的文件IO,则没有太多改进。我认为你唯一能做的就是初始化你的向量,这样它就不会在循环中一直调整大小。使用定义的输入流操作符,它看起来也更清晰:

std::vector<matEntry> matEntries;
matEntries.resize(numberOfLines);
inputfileA.open(matrixAfilename.c_str());

// Read from file to continue setting up sparse matrix A
while(index < numberOfLines && (is >> matEntries[index++]))
{  }

答案 1 :(得分:2)

根据评论中的建议,您应该在尝试优化之前对代码进行概要分析。如果你想尝试随机的东西,直到表现足够好,你可以先尝试将其读入内存。这是一个简单的例子,其中包含一些基本的分析:

#include <vector>
#include <ctime>
#include <fstream>
#include <sstream>
#include <iostream>

// Assuming something like this...
struct matEntry
{
    int row, col;
    double val;
};

std::istream& operator << ( std::istream& is, matEntry& e )
{ 
    is >> matEntry.row >> matEntry.col >> matEntry.val;
    matEntry.row -= 1;
    matEntry.col -= 1;
    return is;
}


std::vector<matEntry> ReadMatrices( std::istream& stream )
{
    auto matEntries = std::vector<matEntry>();

    auto e = matEntry();
    // For why this is better than your EOF test, see https://isocpp.org/wiki/faq/input-output#istream-and-while
    while( stream >> e ) {
        matEntries.push_back( e );
    }
    return matEntries;
}

int main()
{
    const auto time0 = std::clock();

    // Read file a piece at a time
    std::ifstream inputFileA( "matFileA.txt" );
    const auto matA = ReadMatrices( inputFileA );

    const auto time1 = std::clock();

    // Read file into memory (from http://stackoverflow.com/a/2602258/201787)
    std::ifstream inputFileB( "matFileB.txt" );
    std::stringstream buffer;
    buffer << inputFileB.rdbuf();
    const auto matB = ReadMatrices( buffer );

    const auto time2 = std::clock();
    std::cout << "A: " << ((time1 - time0) * CLOCKS_PER_SEC) << "  B: " << ((time2 - time1) * CLOCKS_PER_SEC) << "\n";
    std::cout << matA.size() << " " << matB.size();
}

请注意连续两次读取磁盘上的相同文件,因为磁盘缓存可能会隐藏性能差异。

其他选项包括:

  • 在矢量中预分配空间(可能会根据文件大小添加文件格式或根据文件大小估算它)
  • 将文件格式更改为二进制或压缩数据,以最大限度地缩短读取时间
  • 内存映射文件
  • 并行化( easy :在单独的线程中处理文件A和文件B [请参阅std::async()]; medium :管道,以便完成读取和转换在不同的线程上; :在不同的线程中处理相同的文件)

其他更高级别的考虑可能包括:

  • 看起来你有一个4-D数据阵列(2D矩阵的行/列)。在许多应用中,这是一个错误。花点时间重新考虑一下这个数据结构是否真的符合您的需求。
  • 有许多高质量的矩阵库可用(例如,Boost.QVMBlaze等。使用它们而不是重新发明轮子。

答案 2 :(得分:2)

根据我的经验,这种代码中最慢的部分是解析数值(特别是浮点值)。因此,您的代码很可能受CPU限制,并且可以通过并行化加速,如下所示:

假设您的数据位于 N 行,并且您将使用 k 线程处理它,则每个线程都必须处理[ N / k ]行。

  1. mmap()文件。
  2. 扫描整个文件以获取换行符号,并确定您要分配给每个帖子的范围。
  3. 让每个线程使用implementation of an std::istream that wraps an in-memory buffer)并行处理其范围。
  4. 请注意,这需要确保填充数据结构的代码是线程安全的。