【问题标题】:Read a big file by lines in C++在 C++ 中逐行读取一个大文件
【发布时间】:2015-08-14 09:29:22
【问题描述】:

我有一个将近800M的大文件,想逐行读取。

一开始我用 Python 编写程序,我使用 linecache.getline:

lines = linecache.getlines(fname)

大约需要 1.2 秒。

现在我想将我的程序移植到 C++。

我写了这些代码:

    std::ifstream DATA(fname);
    std::string line;
    vector<string> lines;

    while (std::getline(DATA, line)){
        lines.push_back(line);
    }

但它很慢(需要几分钟)。如何改进?

  • Joachim Pileborg 提到了mmap(),并且在 Windows 上 CreateFileMapping() 可以工作。

我的代码在VS2013下运行,当我使用“DEBUG”模式时,需要162秒;

当我使用“RELEASE”模式时,只有7秒!

非常感谢@DietmarKühl 和@Andrew

【问题讨论】:

  • 您正在运行 C++ 程序的优化版本,对吧?
  • 您的意思是linecache.getline?没有linecache.getlines
  • 第一个例子用空格分割输入。当然会慢一些。
  • 第一个 C++ 代码不读取 lines,它读取的是空格分隔的“单词”。
  • 使用 C++ I/O 流执行时间关键型操作(例如分析)时,最好调用std::ios_base::sync_with_stdio(false)

标签: c++ file ifstream


【解决方案1】:

首先,您可能应该确保在启用优化的情况下进行编译。对于这样一个简单的算法,这可能无关紧要,但这实际上取决于您的向量/字符串库实现。

正如@angew 所建议的,std::ios_base::sync_with_stdio(false) 对您编写的例程有很大影响。

另一个较小的优化是使用lines.reserve() 来预分配你的向量,这样push_back() 就不会导致大量的复制操作。但是,如果您碰巧提前知道大概会收到多少行,这将非常有用。

使用上面建议的优化,我在读取 800MB 文本流时得到以下结果:

 20 seconds ## if average line length = 10 characters
  3 seconds ## if average line length = 100 characters
  1 second  ## if average line length = 1000 characters

如您所见,速度主要取决于每行开销。这种开销主要发生在std::string 类中。

很可能任何基于存储大量std::string 的方法在内存分配开销方面都不是最佳的。在 64 位系统上,std::string 将需要每个字符串最少 16 个字节的开销。事实上,开销很可能会比这大得多 - 您会发现内存分配(std::string 内部)成为一个重要的瓶颈。

为了优化内存使用和性能,请考虑编写自己的例程以大块读取文件,而不是使用getline()。然后,您可以应用类似于 flyweight pattern 的内容来使用自定义字符串类管理各个行的索引。

附:另一个相关因素是物理磁盘 I/O,它可能会或可能不会被缓存绕过。

【讨论】:

    【解决方案2】:

    对于 c++,您可以尝试以下方法:

    void processData(string str)
    {
      vector<string> arr;
      boost::split(arr, str, boost::is_any_of(" \n"));
      do_some_operation(arr);
    }
    
    int main()
    {
     unsigned long long int read_bytes = 45 * 1024 *1024;
     const char* fname = "input.txt";
     ifstream fin(fname, ios::in);
     char* memblock;
    
     while(!fin.eof())
     {
        memblock = new char[read_bytes];
        fin.read(memblock, read_bytes);
        string str(memblock);
        processData(str);
        delete [] memblock;
     }
     return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-27
      • 1970-01-01
      • 2022-01-25
      • 2010-12-24
      • 2010-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多