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);
}

在静态数组代码中,编译器可以告诉内存不再被访问,因为一旦函数返回,它的堆栈就消失了。在动态情况下,它不能,因为它不知道一旦内存被释放,它的值就无关紧要了。第一个循环可能必须保留,但第二个循环可能在动态情况下完全删除。

你没有测量你认为你正在测量的东西。

你可以尝试这样的事情:

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一起移动到循环之后,在静态情况下而不是在动态情况下。(除非微软使用一些技巧来防止这种情况。)

于 2012-12-02T11:17:37.833 回答
2

关于一般的数组访问(而不是您当前的代码),如果您在编译器中打开优化,那么在内存中按顺序访问一堆元素时,动态数组和静态数组之间应该没有任何区别。另一方面,如果关闭了所有优化,那么对于动态数组,存储在指针变量中的内存地址会隐式加载,当您[]在取消引用之前将运算符与指针一起使用时,必须执行此操作地方。所以这是一个额外的操作,静态或堆栈分配的数组不存在。但是同样,打开任何优化,指针都会存储在寄存器中并从那里偏移,因此在第一次访问指针后两者之间不会有任何区别。

于 2012-12-02T11:16:28.007 回答
1

正如 David 上面所说,由于优化,您可能实际上并没有衡量您认为自己是什么。这是您的代码,其中进行了一些更改,以确保没有任何超时被优化。

使用此代码,在 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 回答