为什么istream / ostream很慢

在http://channel9.msdn.com/Events/GoingNative/2013/Writing-Quick-Code-in-Cpp-快速50:40 Andrei Alexandrescu开了一个关于如何不高效/缓慢的istream的笑话。

我以前遇到过一个问题,ostream速度很慢,而且fwrite的速度要快得多(在运行主循环时会减少很多秒),但我从来不理解为什么也不研究它。

是什么让C ++中的istream和ostream变慢? 或者至少比其他的东西(比如fread / fget,fwrite)慢得多,这些东西同样会满足需求。


其实,IOStreams不一定要慢! 不过,这是一个以合理的方式实施它们以快速实现它们的问题。 大多数标准的C ++库似乎并没有太注意实施IOStreams。 很长一段时间,当我的CXXRT仍然保持时,它的速度与stdio一样快 - 正确使用时!

请注意,使用IOStreams的用户性能陷阱很少,但是。 以下指导原则适用于所有IOStream实现,但尤其适用于那些需要快速定制的实现:

  • 当使用std::cinstd::cout等时,你需要调用std::sync_with_stdio(false) ! 没有这个调用,就需要使用标准流对象来与C的标准流同步。 当然,当使用std::sync_with_stdio(false) ,假定您不会将std::cinstdinstd::coutstdout等。
  • 不要使用std::endl因为它要求任何缓冲的许多不必要的刷新。 同样,不要设置std::ios_base::unitbuf或不必要地使用std::flush
  • 在创建自己的流缓冲区(确定,很少用户)时,确保它们使用内部缓冲区! 处理单个字符会跳过多个条件和一个virtual功能,使其变得极其缓慢。

  • 也许这可以让你知道你在处理什么:

    #include <stdio.h>
    #include <iomanip>
    #include <iostream>
    #include <iterator>
    #include <fstream>
    #include <time.h>
    #include <string>
    #include <algorithm>
    
    unsigned count1(FILE *infile, char c) { 
        int ch;
        unsigned count = 0;
    
        while (EOF != (ch=getc(infile)))
            if (ch == c)
                ++count;
        return count;
    }
    
    unsigned int count2(FILE *infile, char c) { 
        static char buffer[8192];
        int size;
        unsigned int count = 0;
    
        while (0 < (size = fread(buffer, 1, sizeof(buffer), infile)))
            for (int i=0; i<size; i++)
                if (buffer[i] == c)
                    ++count;
        return count;
    }
    
    unsigned count3(std::istream &infile, char c) {    
        return std::count(std::istreambuf_iterator<char>(infile), 
                        std::istreambuf_iterator<char>(), c);
    }
    
    unsigned count4(std::istream &infile, char c) {    
        return std::count(std::istream_iterator<char>(infile), 
                        std::istream_iterator<char>(), c);
    }
    
    unsigned int count5(std::istream &infile, char c) {
        static char buffer[8192];
        unsigned int count = 0;
    
        while (infile.read(buffer, sizeof(buffer)))
            count += std::count(buffer, buffer+infile.gcount(), c);
        count += std::count(buffer, buffer+infile.gcount(), c);
        return count;
    }
    
    unsigned count6(std::istream &infile, char c) {
        unsigned int count = 0;
        char ch;
    
        while (infile >> ch)
            if (ch == c)
                ++count;
        return count;
    }
    
    template <class F, class T>
    void timer(F f, T &t, std::string const &title) { 
        unsigned count;
        clock_t start = clock();
        count = f(t, 'N');
        clock_t stop = clock();
        std::cout << std::left << std::setw(30) << title << "tCount: " << count;
        std::cout << "tTime: " << double(stop-start)/CLOCKS_PER_SEC << "n";
    }
    
    int main() {
        char const *name = "equivs2.txt";
    
        FILE *infile=fopen(name, "r");
    
        timer(count1, infile, "ignore");
    
        rewind(infile);
        timer(count1, infile, "using getc");
    
        rewind(infile);
        timer(count2, infile, "using fread");
    
        fclose(infile);
    
        std::ifstream in2(name);
        timer(count3, in2, "ignore");
    
        in2.clear();
        in2.seekg(0);
        timer(count3, in2, "using streambuf iterators");
    
        in2.clear();
        in2.seekg(0);
        timer(count4, in2, "using stream iterators");
    
        in2.clear();
        in2.seekg(0);
        timer(count5, in2, "using istream::read");
    
        in2.clear();
        in2.seekg(0);
        timer(count6, in2, "using operator>>");
    
        return 0;
    }
    

    运行这个,我得到这样的结果(使用MS VC ++):

    ignore                          Count: 1300     Time: 0.309
    using getc                      Count: 1300     Time: 0.308
    using fread                     Count: 1300     Time: 0.028
    ignore                          Count: 1300     Time: 0.091
    using streambuf iterators       Count: 1300     Time: 0.091
    using stream iterators          Count: 1300     Time: 0.613
    using istream::read             Count: 1300     Time: 0.028
    using operator>>                Count: 1300     Time: 0.619
    

    和这(与MinGW):

    ignore                          Count: 1300     Time: 0.052
    using getc                      Count: 1300     Time: 0.044
    using fread                     Count: 1300     Time: 0.036
    ignore                          Count: 1300     Time: 0.068
    using streambuf iterators       Count: 1300     Time: 0.068
    using stream iterators          Count: 1300     Time: 0.131
    using istream::read             Count: 1300     Time: 0.037
    using operator>>                Count: 1300     Time: 0.121
    

    正如我们在结果中可以看到的那样,这不是一个真正的问题,因为iostream的分类速度很慢。 相反,很大程度上取决于您如何使用iostreams(以及FILE *的更小程度)。 这些实现之间也存在相当大的差异。

    尽管如此,每个版本的最快版本( freadistream::read )基本上都是绑定的。 使用VC ++ getcistream::readistreambuf_iterator慢很多。

    底线:从iostreams获得良好的性能需要比FILE *更多的关注 - 但它肯定是可能的。 它们还为您提供了更多选择:当您不关心速度时,便利性和性能与通过C型I / O获得的最佳性能直接竞争,并且只需一些额外的工作。


    在一个类似的话题上,STL说:“你可以调用setvbuf()来在stdout上启用缓冲。”

    https://connect.microsoft.com/VisualStudio/feedback/details/642876/std-wcout-is-ten-times-slower-than-wprintf-performance-bug-in-c-library

    链接地址: http://www.djcxy.com/p/31517.html

    上一篇: Why is istream/ostream slow

    下一篇: separated floats in C++ quickly?