簡體   English   中英

當迭代器是類成員時,為什么 C++ 中的 for 循環更慢

[英]Why is a for loop slower in C++ when the iterator is a class member

這個問題以前是我自己問的,雖然不是很好。 我已經對其進行了重新措辭和擴展,我希望我已經澄清了幾點。 這個問題非常從初學者的角度來看。

下面是一個簡短的示例代碼,它內聯運行並作為函數的一部分。

該代碼將數組的每個元素加 1,然后將每個元素除以 2。 這暫時是任意的,只是更復雜但非常等效的東西的占位符。

作為背景,這阻止了實時應用程序的音頻處理。 這就是原因

int N = 44.1e3 * 60;

所以基本上這將處理以 44.1kHz 采樣的 1 分鍾音頻。

內聯編寫的顯式代碼比函數代碼運行得快得多。 雖然已經聲明了計時器,但它不是一個小差異,而是一個方法在 1 秒內運行而另一個需要大約 8 秒 (ymmv) 的問題。

函數調用將招致開銷的懲罰。 速度可以通過更改優化標志來提高,但距離這兩種方法在相似的時間范圍內運行還差得很遠。

我的問題是:

  1. 可以更改函數調用方法,同時仍作為類中的函數保留,以便它以與內聯方法相似或完全相同的速度運行。?
  2. 是否有任何可以使用的編譯器標志會導致兩種方法在相似的時間范圍內運行? 如果是這樣,它們將如何在 Xcode 中使用,最好是有推薦的資源詳細說明用法。

下面的代碼很簡單,而且在風格上不是很專業。 這是為了減少混亂並希望專注於主要問題。

如果可以對適用於上述問題的類定義進行任何更改,我會全力以赴。 否則,我理解您的不滿,但它可能與此處無關。

提供的時鍾打印輸出不是一個徹底的基准測試工具。 它被包含作為兩種方法之間大時間差的基本說明。

#include <iostream>
#include <sys/time.h>

class MyClass
{
    static const int I = 1000;
    int n, i;
    double foo[I] = {0};

public:
    void myFunction(int N)
    {
        for(n = 0; n < N; n++ )
        {
            for(i = 0; i < I; i++ )
            {
                foo[i]+= 1;
                foo[i]*= .5;
            }
        }
    }
};

int main()
{
    
    int N = 44.1e3 * 60; // number of samples
    
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // The Explicit Approach
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    const int I = 1000;
    double bar[I] = {0};
    
    std::clock_t startTime = std::clock();
    
    for(int n = 0; n < N; n++)
    {
        for(int i = 0; i < I; i++)
        {
            bar[i] += 1;
            bar[i] *=.5;
        }
    }
    
    double duration = ( std::clock() - startTime ) / (double) CLOCKS_PER_SEC;
    
    std::cout << "Explicit Approach Time (seconds): " << duration << '\n';
    
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //  The Class Approach
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    MyClass testClass;
    
    startTime = std::clock();
    
    testClass.myFunction(N);
    
    duration = (std::clock() - startTime) / (double) CLOCKS_PER_SEC;
    
    std::cout << "Class Approach Time (seconds): " << duration << '\n';
    
    return 0;
}

我稍微重新編寫了您的代碼,如下所示:

#include <iostream>
#include <chrono>
#include <cmath>

class someClass {
   int n, i;           // internal class loop indeces
   double foo[1000];
   int I = ::std::floor(sizeof(foo)/sizeof(foo[0])); // number of elements in foo
 public:
   void someFunction(int);
};

void someClass::someFunction(int N)
{
   for(n=N; n--; ) {
      for(i=I; i--; ) {
         foo[i] += 1;
         foo[i] *= .5;
      }
   }
}


int main()
{

    // this was initially an audio processing problem
    // Essentially, process a minute of audio

   int N = 44.1e3 * 60;

   {
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      /// The Explicit Method
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      int n, i;             // loop indeces
      double bar[1000];
      int I = floor(sizeof(bar)/sizeof(bar[0]));

      // START CLOCK
      auto start = ::std::chrono::high_resolution_clock::now();


      // Exactly what is defined in the function 'someFunction' above
      for(n=N;n--; ){
         for(i=I;i--; ){
            bar[i]+= 1;
            bar[i]*=.5;
         }
      }

      // END CLOCK
      auto end = ::std::chrono::high_resolution_clock::now();

      std::chrono::duration<double> duration_secs = end - start;

      std::cout<<"Explicit Method Time (seconds): "<< duration_secs.count() <<'\n';
   }

   {
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      //  The Function Method
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      someClass testClass;

      // START CLOCK
      auto start = ::std::chrono::high_resolution_clock::now();

      testClass.someFunction(N);

      // END CLOCK
      auto end = ::std::chrono::high_resolution_clock::now();

      std::chrono::duration<double> duration_secs = end - start;
      std::cout<<"Member Function Time (seconds): "<< duration_secs.count() <<'\n';
   }

    return 0;
}

我現在得到這個輸出:

$ /tmp/a.out 
Explicit Method Time (seconds): 3.89e-07
Member Function Time (seconds): 1.46e-07

所以,對我來說,顯式方法要慢得多。 盡管他們的時間都還很短,以至於幾乎不值得衡量。 兩者都在數百納秒的數量級上。 令人印象深刻的是計時器的高分辨率足以測量它。

那么,下一個問題是,您使用的是哪個編譯器? 你是為什么平台編譯的?

您的代碼仍有很多不理想的地方。 我剛剛清理了包含,使用 C++11 中的::std::chrono進行計時,並為手動內聯版本和成員函數版本設置了明確的范圍。

我在 gcc 7.2 上用 -O3 編譯。 它仍然包含未定義的行為,因為它使用了一個未初始化的數組。 查看代碼,gcc 意識到數組甚至從未使用過,也沒有生成任何代碼。 所以,基本上,背靠背調用now 手動內聯版本和成員函數之間的時間差異可以完全歸因於基本舍入誤差。

所以,答案是,您的代碼仍然沒有顯示您正在談論的問題,並且您仍然沒有提供足夠的細節。 :-) 要么,要么答案在於您使用的編譯器以及您提供的選項。

以前我自己曾問過這個問題,雖然不是很好。 我已經對其進行了改寫和擴展,希望我澄清了兩點。 從初學者的角度來看,這個問題非常多。

下面是一個簡短的示例代碼,該代碼內聯運行並作為函數的一部分運行。

代碼將1加到數組的每個元素上,然后將每個元素除以2。 目前這是任意的,只是占位符,可以用於更復雜但非常等效的事物。

作為背景,這會阻止實時應用程序的音頻處理。 這就是原因

int N = 44.1e3 * 60;

因此,從本質上講,這將處理1分鍾以44.1kHz采樣的音頻。

內聯編寫的顯式代碼比功能代碼運行得快得多。 盡管已經聲明了計時器,但這並不是一個小小的差異,而是一個方法的問題,一種方法在1秒鍾內運行,另一種方法耗時約8秒鍾(ymmv)。

函數調用將產生開銷的罰款。 可以通過更改優化標志來提高速度,但是沒有什么辦法可以使這兩種方法都在相似的時間范圍內運行。

我的問題是:

  1. 是否可以更改函數調用方法,同時仍將其作為類保留在類中,以使其以與內聯方法相似或完全相同的速度運行?
  2. 是否有任何可以使用的編譯器標志會導致兩種方法在相似的時間范圍內運行? 如果是這樣,它們將如何在Xcode中使用,最好是建議使用資源詳細說明用法。

下面的代碼很簡單,從風格上講不是很專業。 這是為了減少混亂,並希望將注意力集中在主要問題上。

如果可以對類定義進行任何更改以適用於上述問題,我非常高興。 否則,我理解您的不滿,但在這里可能與您無關。

提供的時鍾輸出不是一個全面的基准測試工具。 它包括兩種方法之間較大的時差的基本說明。

#include <iostream>
#include <sys/time.h>

class MyClass
{
    static const int I = 1000;
    int n, i;
    double foo[I] = {0};

public:
    void myFunction(int N)
    {
        for(n = 0; n < N; n++ )
        {
            for(i = 0; i < I; i++ )
            {
                foo[i]+= 1;
                foo[i]*= .5;
            }
        }
    }
};

int main()
{
    
    int N = 44.1e3 * 60; // number of samples
    
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // The Explicit Approach
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    const int I = 1000;
    double bar[I] = {0};
    
    std::clock_t startTime = std::clock();
    
    for(int n = 0; n < N; n++)
    {
        for(int i = 0; i < I; i++)
        {
            bar[i] += 1;
            bar[i] *=.5;
        }
    }
    
    double duration = ( std::clock() - startTime ) / (double) CLOCKS_PER_SEC;
    
    std::cout << "Explicit Approach Time (seconds): " << duration << '\n';
    
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //  The Class Approach
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    MyClass testClass;
    
    startTime = std::clock();
    
    testClass.myFunction(N);
    
    duration = (std::clock() - startTime) / (double) CLOCKS_PER_SEC;
    
    std::cout << "Class Approach Time (seconds): " << duration << '\n';
    
    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM