5

私の現在のプロジェクトでは、大きなデータ配列を操作する必要があります。だから私はどちらが良いかを確認するために愚かなテストを行いますが、以下のコードを試してみると、動的配列は静的配列よりもはるかに遅いことがわかりましたなぜそうですか?または私は何か間違ったことをしていますか?

ここにコードがあります(ここからベクトル(動的に等しい)を削除し、配列(静的に等しい)をブーストします)

結果:静的8、動的7493

#include<iostream>
#include<vector>


using namespace std;
using namespace boost;
double arr_time;
double darr_time;

void arrr()
{
int arr[100000];
LARGE_INTEGER start,end;
QueryPerformanceCounter(&start);

for(int i=0 ; i <100000 ; ++i)
{
    arr[i] = 10 ;
}
for(int i=0 ; i <100000 ; ++i)
{
    int x = arr[i];
}
QueryPerformanceCounter(&end);

arr_time += (end.LowPart - start.LowPart);
}

void darr()
{
int *arr = new int[100000];
LARGE_INTEGER start,end;
QueryPerformanceCounter(&start);

for(int i=0 ; i <100000 ; ++i)
{
    arr[i] = 10 ;
}
for(int i=0 ; i <100000 ; ++i)
{
    int x = arr[i];
}
QueryPerformanceCounter(&end);

darr_time += (end.LowPart - start.LowPart);

delete[] arr;
}

int main(int argc, char** argv)
{
for(int i= 0 ; i <100 ; ++i)
{
    arrr();
    darr();

}
cout<<"\n--------------------\n";
cout<<arr_time<<endl;
cout<<darr_time<<endl;
  return 0;
}
4

3 に答える 3

6

コードは計算する値に対して何も行わないため、コンパイラーはコードをゼロに最適化できます。たとえば、コンパイラはおそらくこれを回します:

void arrr()
{
  int arr[100000];
  LARGE_INTEGER start,end;
  QueryPerformanceCounter(&start);

  for(int i=0 ; i <100000 ; ++i)
  {
      arr[i] = 10 ;
   }
  for(int i=0 ; i <100000 ; ++i)
  {
      int x = arr[i];
  }
  QueryPerformanceCounter(&end);

  arr_time += (end.LowPart - start.LowPart);
}

これに:

void arrr()
{
  LARGE_INTEGER start,end;
  QueryPerformanceCounter(&start);

  QueryPerformanceCounter(&end);

  arr_time += (end.LowPart - start.LowPart);
}

静的配列コードでは、関数が戻るとスタックがなくなるため、コンパイラはメモリが二度とアクセスされないことを通知できます。動的なケースでは、メモリが解放されるとその値が重要ではないことを認識していないため、それはできません。最初のループはそのままにしておく必要がありますが、動的な場合、2番目のループは完全に削除される可能性があります。

あなたはあなたが測定していると思うものを測定していません。

あなたはこのようなことを試すことができます:

void arrr()
{
  int arr[100000];
  LARGE_INTEGER start,end;
  QueryPerformanceCounter(&start);

  for(int i=0 ; i <100000 ; ++i)
  {
      arr[i] = 10 ;
  }
  int x = 0;
  for(int i=0 ; i <100000 ; ++i)
  {
      x += arr[i];
  }
  QueryPerformanceCounter(&end);

  arr_time += (end.LowPart - start.LowPart);
  cout << "x = " << x << endl;
}

別の違いもあります。静的配列の場合、コンパイラは、(のようなQueryPerformanceCounter)外部関数が配列の内容に依存したり変更したりできないことを認識しています。動的な場合、それを知ることはできません。の位置はQueryPerformanceCounter、ループに対して変更できます。たとえば、コンパイラーはQueryPerformanceCounter、静的な場合には両方の呼び出しを一緒に、ループの後に移動できますが、動的な場合には移動できません。(Microsoftがこれを防ぐためにいくつかのトリックを使用した場合を除きます。)

于 2012-12-02T11:17:37.833 に答える
2

一般的な配列アクセス(現在のコードではない)に関して、コンパイラで最適化をオンにすると、メモリ内の一連の要素に順番にアクセスするときに、動的配列と静的配列の間に違いはありません。一方、すべての最適化がオフになっている場合、動的配列の場合、ポインター変数に格納されているメモリアドレスが暗黙的に読み込まれます。これは、間接[]参照が行われる前に、ポインターで演算子を使用するときに実行する必要があります。場所。つまり、これは静的配列やスタック割り当て配列にはない追加の操作です。ただし、最適化をオンにすると、ポインターはレジスターに格納され、そこからオフセットされるため、ポインターに最初にアクセスした後は、2つの間に違いはありません。

于 2012-12-02T11:16:28.007 に答える
1

デビッドが上で言ったように、あなたはあなたが最適化のためにあなたが思っているものを実際に測定していない可能性があります。これは、タイムアウトが発生しないようにいくつかの変更を加えたコードです。

このコードを使用すると、Visual Studio 2008および2010を使用したリリースビルドでは、各関数によって生成されたアセンブリコードとほぼ同じ時間がかかります。私にとって、動的時間は常に静的時間よりもわずかに短いですが、そのようなごくわずかな量で、それらは同等であると言えます。

#include <Windows.h>
#include <iostream>

LONGLONG arrr()
{
    int arr[100000], x = 0;
    LARGE_INTEGER start, end;
    QueryPerformanceCounter(&start);
    for(int i=0; i < 100000; ++i) arr[i] = 10;
    for(int i=0; i < 100000; ++i) x += arr[i];
    QueryPerformanceCounter(&end);
    std::cout << x << std::endl;
    return (end.QuadPart - start.QuadPart);
}

LONGLONG darr()
{
    int *arr = new int[100000], x = 0;
    LARGE_INTEGER start, end;
    QueryPerformanceCounter(&start);
    for(int i=0; i < 100000; ++i) arr[i] = 10;
    for(int i=0; i < 100000; ++i) x += arr[i];
    QueryPerformanceCounter(&end);
    delete[] arr;
    std::cout << x << std::endl;
    return (end.QuadPart - start.QuadPart);
}

int main()
{
    LONGLONG arr_time = 0, darr_time = 0;
    for(int i = 0; i < 100; ++i)
    {
        arr_time += arrr();
        darr_time += darr();
    }
    std::cout<<"\n--------------------\n";
    std::cout << arr_time << std::endl;
    std::cout << darr_time << std::endl;
    return 0;
}
于 2012-12-02T12:30:06.020 に答える