由于memcpy,C++ ifstream :: read很慢

ret*_*998 8 c++ performance fstream memcpy visual-c++

最近我决定优化我正在做的一些文件读取,因为正如大家所说,将大量数据读取到缓冲区然后使用它比使用大量小读取更快.而且我的代码现在肯定要快得多,但在进行一些分析之后,似乎memcpy占用了大量的时间.

我的代码的要点是......

ifstream file("some huge file");
char buffer[0x1000000];
for (yada yada) {
    int size = some arbitrary size usually around a megabyte;
    file.read(buffer, size);
    //Do stuff with buffer
}
Run Code Online (Sandbox Code Playgroud)

我正在使用Visual Studio 11,在对我的代码进行分析后,它ifstream::read()最终会调用xsgetn()从内部缓冲区到我的缓冲区的副本.此操作占用超过80%的时间!排在第二位的是uflow()10%的时间.

有什么方法可以绕过这个复制吗?我可以以某种方式告诉我ifstream将我需要的大小缓冲到我的缓冲区吗?C风格FILE*也使用这样的内部缓冲区吗?

更新:由于人们告诉我使用cstdio ...我做了一个基准测试.

编辑:不幸的是旧的代码充满了失败(它甚至没有读取整个文件!).你可以在这里看到它:http://pastebin.com/4dGEQ6S7

这是我的新基准:

const int MAX = 0x10000;
char buf[MAX];
string fpath = "largefile";
int main() {
    {
        clock_t start = clock();
        ifstream file(fpath, ios::binary);
        while (!file.eof()) {
            file.read(buf, MAX);
        }
        clock_t end = clock();
        cout << end-start << endl;
    }
    {
        clock_t start = clock();
        FILE* file = fopen(fpath.c_str(), "rb");
        setvbuf(file, NULL, _IOFBF, 1024);
        while (!feof(file)) {
            fread(buf, 0x1, MAX, file);
        }
        fclose(file);
        clock_t end = clock();
        cout << end-start << endl;
    }
    {
        clock_t start = clock();
        HANDLE file = CreateFile(fpath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL, NULL);
        while (true) {
            DWORD used;
            ReadFile(file, buf, MAX, &used, NULL);
            if (used < MAX) break;
        }
        CloseHandle(file);
        clock_t end = clock();
        cout << end-start << endl;
    }
    system("PAUSE");
}
Run Code Online (Sandbox Code Playgroud)

时间是:
185
80
78

好吧......看起来使用C风格的fread比ifstream :: read更快.同样,使用Windows ReadFile只能提供一点点优势,这可以忽略不计(我看了代码,fread基本上是ReadFile的包装器).看起来我毕竟会转向恐惧.

男人写一个基准,实际上正确地测试这个东西是很困惑的.

结论:使用<cstdio>速度快于<fstream>.fstream较慢的原因是因为c ++流有自己的内部缓冲区.每当您进行读/写操作时,这会导致额外的复制,并且此复制会占用fstream所需的整个额外时间.更令人震惊的是,所花费的额外时间比实际读取文件所花费的时间长.

Cub*_*bbi 5

我可以以某种方式告诉ifstream将我需要的大小缓冲到我的缓冲区吗?

是的,这就是pubsetbuf()的用途.

但是,如果您关心的是复制读取文件,也可以考虑内存映射,boost有一个可移植的实现.


orl*_*rlp 2

如果你想加速文件 I/O,我建议你使用好 ol',<cstdio>因为它可以大大优于 C++。

  • 这只是错误的。使用带有编译器优化的“istream::read”的 C++ 惯用解决方案与 C 解决方案一样快。例如http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html 我自己用VS2013确认了这些结果。 (3认同)
  • @retep998:类没有开销。虚函数*做*。问题不在于缓冲,而在于缓冲。`xsgetn` 正在执行文件 IO。但它也做一些事情,比如为角色调用“codecvt”。 (2认同)