Why is istream/ostream slow

后端 未结 4 1581
-上瘾入骨i
-上瘾入骨i 2020-12-04 17:51

At 50:40 of http://channel9.msdn.com/Events/GoingNative/2013/Writing-Quick-Code-in-Cpp-Quickly Andrei Alexandrescu makes a joke about how not efficient/slow istream is.

4条回答
  •  悲哀的现实
    2020-12-04 18:51

    Perhaps this can give some idea of what you're dealing with:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    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(infile), 
                        std::istreambuf_iterator(), c);
    }
    
    unsigned count4(std::istream &infile, char c) {    
        return std::count(std::istream_iterator(infile), 
                        std::istream_iterator(), 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 
    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;
    }
    

    Running this, I get results like this (with 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
    

    and this (with 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
    

    As we can see in the results, it's not really a matter of iostreams being categorically slow. Rather, a great deal depends on exactly how you use iostreams (and to a lesser extent FILE * as well). There's also a pretty substantial variation just between these to implementations.

    Nonetheless, the fastest versions with each (fread and istream::read) are essentially tied. With VC++ getc is quite a bit slower than either istream::read or and istreambuf_iterator.

    Bottom line: getting good performance from iostreams requires a little more care than with FILE * -- but it's certainly possible. They also give you more options: convenience when you don't care all that much about speed, and performance directly competitive with the best you can get from C-style I/O, with a little extra work.

提交回复
热议问题