zoukankan      html  css  js  c++  java
  • 关于iostream的效率问题

    前言
        经常有人说iostream的速度慢,IO流比stdio的慢多了。但是有人测试过的,iostream的速度是超过stdio的。

    测试结果

    /* C */
    #include <stdio.h>

    int main()
    {
        FILE* stream;
        size_t num;
        size_t sum = 0;
        size_t i = 0;

        stream = fopen("random.data", "r");
        while(fscanf(stream, "%u", &num) != EOF)
        {
            sum += num;
        }
        fclose(stream);

        printf("%u ", sum);
        return 0;
    }

    /* C++ */
    #include <iostream>
    #include <fstream>

    using namespace std;

    int main()
    {
        ifstream stream("random.data");
        size_t num;
        size_t sum = 0;

        while(stream >> num)
        {
            sum += num;
        }
        cout << sum << endl;
        return 0;
    }

    random.data中为100000个0-32767的随机数

    C版本平均用时0.64s,C++平均用时0.58s

    于是又把这陈芝麻烂谷子事拿出来研究。单步VC10/11(用后者是因为新版加入了chrono方便计时),cout输出一段字符串的调用顺序如下:

     


    operator<< => sputn => xsputn => overflow => _Fputc => fputc
    cout封装了fputc一个字符一个字符的输出,而Win下默认不给stdout开buffer,于是造成cout输出字符串极度缓慢,杯具出现了
    想起线程安全性问题。cout虽然线程安全(原文:http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx),但是输出的字符是混在一起的,我猜想也是cout封装fputc而在fputc里加锁的原因。

    看printf()的源码:
        va_start(arglist, format);

        _lock_str2(1, stdout);
        __try {
    // int _stbuf(stream) - set temp buffer on stdout, stdprn, stderr
            buffing = _stbuf(stdout);

            retval = _output_l(stdout,format,NULL,arglist);

    // void _ftbuf(flag, stream) - take temp buffering off a stream
            _ftbuf(buffing, stdout);

        }
        __finally {
            _unlock_str2(1, stdout);
        }
    首先将stdout整体加锁,然后给stdout开了一个临时buffer,输出后再刷新,显然要比cout快得多。

    测试用了fstream,文件指针在win下是默认开buffer的,于是给cout手动开buffer,前后测试结果如下:

    未开buffer:

     




    开了buffer:

     




    可以看到未开buffer时cout的用时比printf慢数十倍,开buffer后的用时与printf已经十分接近(cout绑定stdout,给cout开buffer就等于给printf开buffer),造成的差异应该是每个字符分别加锁的缘故。另外printf用%s输出比直接输出快,大概是因为直接输出的话解析格式字符串时每个字符都要判断format[n]=='%'

    这是g++ MinGW-w64的测试结果:
    未开buffer:

     



    开了buffer:

     



    stdlibc++使用了不同的封装方式,未开buffer时两者速度已经较为接近,开buffer后已经超过用printf直接输出。

    关于g++和VC的速度比较,除了原生64位以外,CRT也有差距,毕竟VC是微软自己的东西
    注:mingw的cout.rdbuf()->pubsetbuf似乎有问题,改用setvbuf

    附虚拟机下Fedora 16(g++ 4.6.2)测试结果(linux默认给stdout开buffer)

     




    TIP:
       关于cout输出慢,可能是buffer刷新的问题 把endl换成' '就会快上许多了。

     

  • 相关阅读:
    使用pycharm专业版(支持远程调试及运行)如何运行mpi的代码呢???(mpi4py的代码)
    使用MPI时执行代码时运行命令中参见的几种参数设置
    多网卡系统下如何使用tcp协议实现MPI的分布式多机运行(mpi的实现使用openmpi)
    为什么我要弃用华为的软件产品——mindspore从入门到放弃之感想
    网络文件系统nfs服务端配置客户端权限时的demo例子
    【转载】 NFS服务器端的权限设置学习 Linux运维学习
    Ubuntu18.04系统下网络文件系统nfs的安装及简单配置
    【转载】 Sun RPC 编程简介
    【转载】 SUN RPC的传输层实现机制 —— rpcbind(nfs文件系统中的rpc)
    【转载】sun的rpc ——rpcbind(nfs文件系统中的rpc)
  • 原文地址:https://www.cnblogs.com/foohack/p/3582272.html
Copyright © 2011-2022 走看看