【问题标题】:Performance difference of getline operating with istream and FILE*使用 istream 和 FILE 操作的 getline 的性能差异*
【发布时间】:2018-01-06 02:43:11
【问题描述】:

我正在尝试逐行比较读取文件的性能。第一种情况是字符串和 istream 的 getline,第二种情况是 char* 和 FILE* 的 getline。我想知道:

  1. 为什么第一种情况这么慢?
  2. 是否可以让 C++ sn-p 更快?

考虑下面的输出(首先是 ifstream):

Lines count: 10628126
ifstream getline: 43.2684
Lines count: 10628126
fopen getline: 1.06217

文件*优先:

Lines count: 10628126
fopen getline: 1.96065
Lines count: 10628126
ifstream getline: 43.0428

我用于测试的代码:

#include <fstream>
#include <iostream>
#include <string>

#include <sys/time.h>
#include <stdio.h>


using namespace std;

double gettime()
{
    double result = 0;
    struct timeval tv = {0};
    struct timezone tz = {0};
    gettimeofday(&tv, &tz);
    result = tv.tv_sec + (1.0 * tv.tv_usec / 1000000);
    return result;
}

void read_cpp(const char * filename)
{
    ifstream ifile(filename);
    string line;
    unsigned int i = 0;
    while(getline(ifile, line)) i++;
    cout << "Lines count: " << i << endl;
}

void read_c(const char * filename)
{
    FILE * ifile = fopen(filename, "r");
    size_t linesz = 4096+1;
    char * line = new char[linesz];
    unsigned int i = 0;
    while(getline(&line, &linesz, ifile) > 0) i++;
    delete[] line;
    cout << "Lines count: " << i << endl;
    fclose(ifile);
}

int main(int argc, char * argv[])
{
    double tmstart;
    tmstart = gettime();
    read_cpp(argv[1]);
    cout << "ifstream getline: " << (gettime() - tmstart) << endl;
    tmstart = gettime();
    read_c(argv[1]);
    cout << "fopen getline: " << (gettime() - tmstart) << endl;
}

附:我尝试交换 read_cpp 和 read_c 几乎没有区别。

更新

看来@Galik 和@geza 使用g++ 编译器无法重现该问题,所以我在linux 环境下检查了代码,C 和C++ 实现。所以这似乎是一个环境问题。最初我使用 Mac OS X 和默认的 C++ 编译器 clang 测量时间(让我感到惊讶):

$ g++ -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

但所有这些事情在真正的g++ 中从未发生过:

$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ...
Thread model: posix
gcc version 4.9.2 (Debian 4.9.2-10)

抱歉,给您带来不便。

更新2

我找到了相关主题clang++ fstreams 10X slower than g++。作者还面临着clang编译的代码性能下降的问题。要解决此问题,可以使用不同的 stdlib 实现 (-stdlib=stdlibc++) 而不是默认的 (-stdlib=libc++)。在这种情况下,clang 将显示弃用警告:

clang: warning: libstdc++ is deprecated; move to libc++ [-Wdeprecated]

但性能会好很多(即使没有优化):

Lines count: 10628126
fopen getline: 1.02899
Lines count: 10628126
ifstream getline: 1.67594

【问题讨论】:

  • 你试过在read_cpp()之前调用read_c()吗?
  • c++ 流可能更慢,因为幕后发生的事情更多,C++ 流缓冲可能更快。但是,缓存也可能在这里起作用。交换这两种阅读方法可能会有所帮助,看看这是否对性能有显着影响(Mike Nakis 击败了这一点)。
  • 您是否在打开优化的情况下进行编译?
  • 使用您的确切代码并使用-O3 编译它们对我来说运行的时间差不多。 (GCC v.7.1.0)
  • 您使用哪种操作系统和编译器?我也不能用 linux 和 gcc 6.3 重现这个。 ifstream 较慢,但差异约为 10%(对于 1.3GB 文本文件)。

标签: c++ ifstream getline


【解决方案1】:

c++ 版本做了更多的边界检查、语言环境解释和 iostream 状态管理。它非常强大。

c 版本是极简的,而且更脆弱。

安全和实用是有代价的。

价格就是时间。

更新:

c readline 期望使用 malloc 和 free,而不是 new 和 delete。

这里是更正的版本:

#include <cstdlib>
#include <cstdio>
#include <iostream>

void read_c(const char * filename)
{
    FILE * ifile = fopen(filename, "r");
    size_t linesz = 0;
    char * line = nullptr;
    unsigned int i = 0;
    while(getline(&line, &linesz, ifile) > 0) i++;
    free(line);
    std::cout << "Lines count: " << i << std::endl;
    fclose(ifile);
}

【讨论】:

  • 有没有其他方法可以读取具有最小副作用和优化的文件?换句话说,是否可以使用 C++ STL 实现 read_c?
  • @frist 如果你想如果你想要的只是分隔的字符串,你的版本很好。但是,有一种方法可以使其更安全。我会发布更新。
  • 我不会打电话给 C getline() 脆弱的。它只是从由换行符分隔的文件中读取块。另一方面,[f]scanf() 非常脆弱,几乎无法使用。
猜你喜欢
  • 2014-02-02
  • 2012-02-18
  • 1970-01-01
  • 2014-07-16
  • 2013-01-18
  • 2011-09-17
  • 2019-06-15
  • 2016-01-24
  • 1970-01-01
相关资源
最近更新 更多