在c ++中最快的方式将stdin的内容读入字符串或向量

时间:2015-10-05 17:33:24

标签: c++ string file-io vector

许多stackoverflow答案涉及如何从磁盘中啜饮文件,您可以根据文件大小预先分配内存。

但是什么是在stdin中啜饮的最快方法(例如,当一个大文件通过管道进入你的程序时)?

如果这是最快的解决方案,我很乐意进入一个向量(后来总是可以转换为std :: string)。

2 个答案:

答案 0 :(得分:2)

将未格式化的数据读入内存的最快方法是使用未格式化的读取例程。例如,fstream :: read()。什么都不会打败它。

小心!有些人声称通过使用操作系统级例程(如read())可以看到性能提升。如果你试试这个,你会得到极大的性能下降。

EDIT。对上述陈述的一些解释。降级的原因是内核调用。每次读取都是内核调用,因此除非您准确读取最佳数据缓冲区的大小,否则将会引发更多内核调用或不太理想的读取。虽然您可以通过实验确定最佳读取大小,但C运行时已经为您完成了此操作。 fread()和未格式化的流读取已经过优化,因此无论读取块有多大,都可以保证以最佳方式调用内核。

答案 1 :(得分:0)

在循环中读入固定大小的缓冲区

令我惊讶的是,老式的,几乎像c的代码似乎是clang和gcc中最快的代码:

{
    vector<char> cin_str;
    // 64k buffer seems sufficient
    std::streamsize buffer_sz = 65536;
    vector<char> buffer(buffer_sz);
    cin_str.reserve(buffer_sz);

    auto rdbuf = cin.rdbuf();
    while (auto cnt_char = rdbuf->sgetn(buffer.data(), buffer_sz))
        cin_str.insert(cin_str.end(), buffer.data(), buffer.data() + cnt_char);
}

使用istream::read()istream::gcount()同样快,但需要一些额外的代码......

c ++迭代器

令人惊讶的是,使用istreambuf_iterator未格式化输入的迭代器)变得更慢,更慢:&gt;对于某些测试文件来说是3倍,即使在关闭与stdio同步之后也是如此。< / p>

{
    std::ios_base::sync_with_stdio(false) ;
    vector<char> cin_str;
    //              64k
    std::streamsize buffer_sz = 65536;
    cin_str.reserve(buffer_sz);

    std::istreambuf_iterator<char> iit (std::cin.rdbuf()); // stdin iterator
    std::istreambuf_iterator<char> eos;                    // end-of-range iterator
    std::copy(iit, eos, std::back_inserter(cin_str));
    return cin_str;
}

即使为vector缓冲区保留空间(而不仅仅是分配给它),也是如此。

另一个令人惊讶的是,即使具有非常适度的缓冲区大小(64 kb),也能看到(接近)最大速度。 vector只是一个非常有效的重新分配策略。

附录:

Google-ing发现此博文

来自2011年的

http://insanecoding.blogspot.in/2011/11/reading-in-entire-file-at-once-in-c.html)似乎表明这种方法与c ++(gcc / clang)一样快,而切换到cstdio并没有提供进一步的收益(但显然使得代码甚至更丑!)。

避免副本

@BenVoigt指出,如果我们明智地预先分配必要的空间,那么读取数据可以由sgetn() / istream::read()放置到位:

{
    std::ios_base::sync_with_stdio(false) ;
    //              64k
    std::streamsize buffer_sz = 65536;
    vector<char> cin_str(buffer_sz);
    std::streamsize cin_str_data_end = 0U;

    auto rdbuf = cin.rdbuf();
    while (auto cnt_char = rdbuf->sgetn(cin_str_data_end + cin_str.data(), buffer_sz))
    {
        cin_str_data_end += cnt_char;
        cin_str.resize(cin_str_data_end + buffer_sz);
    }
    cin_str.resize(cin_str_data_end);
    return cin_str;
}

在测试中,这导致没有进一步的加速可能因为这个代码主导1)i / o 2)系统调用开销3)向量内存分配

有更快的方法吗?来自boost的内存映射文件?