STL算法是否针对速度进行了优化?

时间:2015-03-17 23:00:30

标签: c++ algorithm stl

我正在测试std :: vector上不同方式循环的速度。 在下面的代码中,我考虑了5种方法来计算N = 10000000个元素的向量的所有元素的总和:

  1. 使用迭代器
  2. 使用整数索引
  3. 使用整数索引,展开因子2
  4. 使用整数索引,展开因子4
  5. 使用std :: accumulate
  6. 代码使用g ++ for windows编译,用于编译的命令行是:

    g++ -std=c++11 -O3 loop.cpp -o loop.exe
    

    我运行了4次代码,测量每种方法的时间,得到以下结果(以微秒为单位的时间,给出最大值和最小值):

    • 迭代器:8002 - 8007
    • Int指数:8004 - 9003
    • 展开2:6004 - 7005
    • 展开4:4001 - 5004
    • 累积:8005 - 9007

    这些实验似乎表明:

    1. 使用迭代器与整数索引进行循环并没有多大区别,至少在完全优化时是这样。

    2. 展开循环可以获得回报

    3. 令人惊讶的是,stl :: accumulate的性能更差。

    4. 虽然结论1和2有些预期,但数字3却令人惊讶。不是所有的书都说使用STL算法而不是自己写循环吗?

      我在衡量时间或者解释结果的方式上是否犯了任何错误? 如果您尝试下面给出的代码,你们会得到一个不同的场景吗?

      #include <iostream>
      #include <chrono>
      #include <vector>
      #include <numeric>
      
      using namespace std;
      using namespace std::chrono;
      
      
      
      int main()
      {
          const int N = 10000000;
          vector<int> v(N);
          for (int i = 0; i<N; ++i)
              v[i] = i;
      
          //looping with iterators
          {
              high_resolution_clock::time_point t1 = high_resolution_clock::now();
      
              long long int sum = 0;
              for (auto it = v.begin(); it != v.end(); ++it)
                  sum+=*it;
      
              high_resolution_clock::time_point t2 = high_resolution_clock::now();
      
              auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
      
              cout << duration << "microseconds  output = " << sum << " (Iterators)\n";
          }
      
          //looping with integers
          {
              high_resolution_clock::time_point t1 = high_resolution_clock::now();
      
              long long int sum = 0;
              for (int i = 0; i<N; ++i)
                  sum+=v[i];
      
              high_resolution_clock::time_point t2 = high_resolution_clock::now();
      
              auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
      
              cout << duration << "microseconds  output = " << sum << " (integer index)\n";
          }
      
          //looping with integers (UNROLL 2)
          {
              high_resolution_clock::time_point t1 = high_resolution_clock::now();
      
              long long int sum = 0;
              for (int i = 0; i<N; i+=2)
                  sum+=v[i]+v[i+1];
      
              high_resolution_clock::time_point t2 = high_resolution_clock::now();
      
              auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
      
              cout << duration << "microseconds  output = " << sum << " (integer index, UNROLL 2)\n";
          }
      
          //looping with integers (UNROLL 4)
          {
              high_resolution_clock::time_point t1 = high_resolution_clock::now();
      
              long long int sum = 0;
              for (int i = 0; i<N; i+=4)
                  sum+=v[i]+v[i+1]+v[i+2]+v[i+3];
      
              high_resolution_clock::time_point t2 = high_resolution_clock::now();
      
              auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
      
              cout << duration << "microseconds  output = " << sum << " (integer index, UNROLL 4)\n";
          }
      
          //using std::accumulate
          {
              high_resolution_clock::time_point t1 = high_resolution_clock::now();
      
              long long int sum = accumulate(v.begin(), v.end(), static_cast<long long int>(0));
      
              high_resolution_clock::time_point t2 = high_resolution_clock::now();
      
              auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
      
              cout << duration << "microseconds  output = " << sum << " (std::accumulate)\n";
          }
          return 0;
      }
      

2 个答案:

答案 0 :(得分:3)

使用标准库算法的原因是而不是以获得更高的效率,它允许您在更高的抽象级别进行思考。

虽然在某些情况下算法会比您自己的手动代码更快,但这并不是他们所需要的。 C ++的一大优势是它允许您在有特定需求时绕过内置库。如果您的基准测试表明标准库导致严重减速,您可以自由地探索循环展开等经典替代方案。对于大多数目的而言,这是永远不必要的。

话虽如此,一个编写良好的标准库算法永远不会比你自己的直接实现慢得多,除非你利用你对数据细节的了解。

答案 1 :(得分:0)

除了Mar,我还是会这么想的 在大多数情况下,STL并不比你自己的实现更快,因为它是一系列相关问题的通用解决方案,但不适用于特定问题,因此STL可能需要考虑的因素多于你真正需要的因素,因此效率较低。 但有一个例外: stl :: sort使用细微的优化(可能是不同排序算法的混合),因此它比通常的实现更快。