大多数学习 C 的 C++ 用户更喜欢使用 printf/scanf 系列函数,即使他们使用 C++ 编码。

虽然我承认我发现界面更好(尤其是类似 POSIX 的格式和本地化),但似乎压倒性的关注是性能。

看看这个问题:



似乎最好的答案是使用 fscanf 并且 C++ ifstream 始终慢 2-3 倍。

我认为如果我们可以编译一个“技巧”存储库来提高 IOStreams 的性能,什么有效,什么无效,那就太好了。

需要考虑的要点

  • 缓冲 ( rdbuf()->pubsetbuf(buffer, size) )
  • 同步(std::ios_base::sync_with_stdio)
  • 语言环境处理(我们可以使用精简的语言环境,还是完全删除它?)

  • 当然,也欢迎其他方法。

    注意:提到了 Dietmar Kuhl 的"new"实现,但我无法找到有关它的许多细节。以前的引用文献似乎是死链接。

    最佳答案

    以下是我到目前为止收集的内容:

    缓冲 :

    如果默认情况下缓冲区很小,增加缓冲区大小肯定可以提高性能:

  • 它减少了硬盘命中数
  • 它减少了系统调用的数量

  • 可以通过访问底层 streambuf 实现来设置缓冲区。
    char Buffer[N];
    
    std::ifstream file("file.txt");
    
    file.rdbuf()->pubsetbuf(Buffer, N);
    // the pointer reader by rdbuf is guaranteed
    // to be non-null after successful constructor
    

    @iavr 提供的警告:根据 cppreference,最好在打开文件之前调用 pubsetbuf。否则,各种标准库实现具有不同的行为。

    区域设置处理:

    Locale 可以执行字符转换、过滤以及涉及数字或日期的更聪明的技巧。它们经历了一个复杂的动态调度和虚拟调用系统,因此删除它们可以帮助减少惩罚。

    默认的 C 语言环境意味着不执行任何转换以及跨机器统一。这是一个很好的默认使用。

    同步:

    使用此工具我看不到任何性能改进。

    可以使用 std::ios_base 静态函数访问全局设置(sync_with_stdio 的静态成员)。

    测量值:

    玩这个,我玩弄了一个简单的程序,在 SUSE 10p3 上使用 gcc 3.4.2-O2 编译。



    对于默认代码,这代表了大约 20% ... 的减速。实际上,篡改缓冲区(在 C 或 C++ 中)或同步参数 (C++) 并没有产生任何改进。

    其他人的结果:



    C++ 快 25%



    C++ 快 17%



    C++ 慢 111%



    C++ 66% 快

    所以答案是:这是一个实现质量问题,实际上取决于平台:/

    对于那些对基准测试感兴趣的人,这里有完整的代码:
    #include <fstream>
    #include <iostream>
    #include <iomanip>
    
    #include <cmath>
    #include <cstdio>
    
    #include <sys/time.h>
    
    template <typename Func>
    double benchmark(Func f, size_t iterations)
    {
      f();
    
      timeval a, b;
      gettimeofday(&a, 0);
      for (; iterations --> 0;)
      {
        f();
      }
      gettimeofday(&b, 0);
      return (b.tv_sec * (unsigned int)1e6 + b.tv_usec) -
             (a.tv_sec * (unsigned int)1e6 + a.tv_usec);
    }
    
    
    struct CRead
    {
      CRead(char const* filename): _filename(filename) {}
    
      void operator()() {
        FILE* file = fopen(_filename, "r");
    
        int count = 0;
        while ( fscanf(file,"%s", _buffer) == 1 ) { ++count; }
    
        fclose(file);
      }
    
      char const* _filename;
      char _buffer[1024];
    };
    
    struct CppRead
    {
      CppRead(char const* filename): _filename(filename), _buffer() {}
    
      enum { BufferSize = 16184 };
    
      void operator()() {
        std::ifstream file(_filename, std::ifstream::in);
    
        // comment to remove extended buffer
        file.rdbuf()->pubsetbuf(_buffer, BufferSize);
    
        int count = 0;
        std::string s;
        while ( file >> s ) { ++count; }
      }
    
      char const* _filename;
      char _buffer[BufferSize];
    };
    
    
    int main(int argc, char* argv[])
    {
      size_t iterations = 1;
      if (argc > 1) { iterations = atoi(argv[1]); }
    
      char const* oldLocale = setlocale(LC_ALL,"C");
      if (strcmp(oldLocale, "C") != 0) {
        std::cout << "Replaced old locale '" << oldLocale << "' by 'C'\n";
      }
    
      char const* filename = "largefile.txt";
    
      CRead cread(filename);
      CppRead cppread(filename);
    
      // comment to use the default setting
      bool oldSyncSetting = std::ios_base::sync_with_stdio(false);
    
      double ctime = benchmark(cread, iterations);
      double cpptime = benchmark(cppread, iterations);
    
      // comment if oldSyncSetting's declaration is commented
      std::ios_base::sync_with_stdio(oldSyncSetting);
    
      std::cout << "C  : " << ctime << "\n"
                   "C++: " << cpptime << "\n";
    
      return 0;
    }
    

    关于c++ - 如何让 IOStream 表现得更好?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5166263/

    10-13 06:44