繁体   English   中英

C ++数组与向量

[英]C++ Array vs vector

当使用C ++向量时,花费的时间是718毫秒,而当我使用Array时,时间几乎是0毫秒。

为什么这么大的性能差异?

int _tmain(int argc, _TCHAR* argv[])
{
const int size = 10000; 
clock_t start, end; 
start = clock();
vector<int> v(size*size); 
for(int i = 0; i < size; i++)
{  
    for(int j = 0; j < size; j++)
    {   
        v[i*size+j] = 1;  
    } 
} 
end = clock();
cout<< (end - start)
    <<" milliseconds."<<endl; // 718 milliseconds

int f = 0;
start = clock(); 
int arr[size*size]; 
for(int i = 0; i < size; i++)
{  
    for(int j = 0; j < size; j++)
    {   
        arr[i*size+j] = 1;  
    } 
} 
end = clock();
cout<< ( end - start)
    <<" milliseconds."<<endl; // 0 milliseconds
return 0;
}

您的数组arr在堆栈上分配,即编译器在编译时计算了必要的空间。 在该方法的开头,编译器将插入一个汇编语句

sub esp, 10000*10000*sizeof(int)

这意味着堆栈指针( esp )减少10000 * 10000 * sizeof(int)字节,以便为10000 2个整数的数组腾出空间。 这个操作几乎是即时的。

向量是堆分配的,堆分配要贵得多。 当向量分配所需的内存时,它必须向操作系统询问连续的内存块,并且操作系统必须执行大量工作才能找到这块内存。

正如安德烈亚斯在评论中所说的那样,你所有的时间都花在这一行上:

vector<int> v(size*size); 

访问循环内的向量与数组一样快。

有关其他概述,请参阅例如

编辑:

在关于性能优化和编译器设置的所有评论之后,我今天早上做了一些测量。 我必须设置size=3000所以我用大约十分之一的原始条目进行测量。 在2.66 GHz Xeon上执行的所有测量:

  1. 使用Visual Studio 2008中的调试设置(无优化,运行时检查和调试运行时),矢量测试花费了920 ms,而阵列测试则为0 ms。

    vector::operator[]花费了98,48%的总时间,即确实花费在运行时检查上的时间。

  2. 通过完全优化,矢量测试需要56 ms(具有原始条目数的十分之一),而阵列的测试时间为0 ms。

    vector ctor需要61.72%的应用程序运行时间。

所以我想根据所使用的编译器设置,每个人都是正确的。 OP的时序表明优化的构建或STL没有运行时检查。

与往常一样,士气是:配置文件优先,优化第二。

如果您使用Microsoft编译器进行编译,为了使其公平比较,您需要通过定义_SECURE_SCL = 0和_HAS_ITERATOR_DEBUGGING = 0来关闭迭代器安全检查和迭代器调试。

其次,您使用的构造函数将每个向量值初始化为零,并且在填充之前您不会将数组memset为零。 所以你要遍历矢量两次。

尝试:

vector<int> v; 
v.reserve(size*size);

将作业更改为例如。 arr[i*size+j] = i*j ,或其他一些非常量表达式。 我认为编译器优化了整个循环,因为从不使用赋值,或者用一些预先计算的值替换数组,因此循环甚至不执行,你得到0毫秒。

将1更改为i*ji得到了向量和数组的相同时序,除非将-O1标志传递给gcc,然后在两种情况下我得到0毫秒。

因此,首先,仔细检查您的循环是否实际执行。

为了得到公平的比较,我认为以下内容应该是合适的:

#include <sys/time.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <numeric>


int main()
{
  static size_t const size = 7e6;

  timeval start, end;
  int sum;

  gettimeofday(&start, 0);
  {
    std::vector<int> v(size, 1);
    sum = std::accumulate(v.begin(), v.end(), 0);
  }
  gettimeofday(&end, 0);

  std::cout << "= vector =" << std::endl
        << "(" << end.tv_sec - start.tv_sec
        << " s, " << end.tv_usec - start.tv_usec
        << " us)" << std::endl
        << "sum = " << sum << std::endl << std::endl;

  gettimeofday(&start, 0);
  int * const arr =  new int[size];
  std::fill(arr, arr + size, 1);
  sum = std::accumulate(arr, arr + size, 0);
  delete [] arr;
  gettimeofday(&end, 0);

  std::cout << "= Simple array =" << std::endl
        << "(" << end.tv_sec - start.tv_sec
        << " s, " << end.tv_usec - start.tv_usec
        << " us)" << std::endl
        << "sum = " << sum << std::endl << std::endl;
}

在这两种情况下,都会执行动态分配和释放,以及对元素的访问。

在我的Linux机器上:

$ g++ -O2 foo.cpp 
$ ./a.out 
= vector =
(0 s, 21085 us)
sum = 7000000

= Simple array =
(0 s, 21148 us)
sum = 7000000

std::vector<>和数组案例都具有可比性。 关键是如果你的代码结构合理, std::vector<>可以和简单数组一样快。


在相关的说明中,关闭优化会在这种情况下产生巨大的差异:

$ g++ foo.cpp 
$ ./a.out 
= vector =
(0 s, 120357 us)
sum = 7000000

= Simple array =
(0 s, 60569 us)
sum = 7000000

Neil和jalf等人提出的许多优化断言完全正确。

HTH!

编辑 :更正代码以强制矢量销毁包含在时间测量中。

您可能正在使用VC ++,在这种情况下,默认情况下,标准库组件在运行时执行许多检查(例如,索引是否在范围内)。 通过将一些宏定义为0(我认为_SECURE_SCL )可以关闭这些检查。

另一件事是我甚至无法按原样运行你的代码:自动数组对于堆栈来说太大了。 当我使它全局化时,那么使用MingW 3.5,我得到的时间是向量627 ms和数组26875 ms(!!),这表明这个大小的数组确实存在很大的问题。

至于这个特定的操作(填充值1),你可以使用vector的构造函数:

std::vector<int> v(size * size, 1);

和数组的填充算法:

std::fill(arr, arr + size * size, 1);

两件事情。 一,运算符[]对于向量来说要慢得多。 二,当你一次添加一个元素时,大多数实现中的向量都会表现得很奇怪。 我并不仅仅意味着它会分配更多的内存,但它有时会做一些真正奇怪的事情。

第一个是主要问题。 对于仅仅百万字节,即使重新分配内存十几次也不应该花费很长时间(它不会在每个添加的元素上执行)。

在我的实验中,预分配并没有太多改变它的缓慢程度。 当内容是实际的对象时,如果你尝试做一些简单的事情,比如对它进行排序,它基本上会停止。

结论,不要将stl或mfc向量用于任何大的或计算重的东西。 它们执行得很慢/很慢并导致大量内存碎片。

声明数组时,它存在于堆栈(或静态内存区域)中,它非常快,但不能增加它的大小。

声明向量时,它会分配动态内存,它不是那么快,但在内存分配方面更灵活,因此您可以更改大小而不是将其标注为最大大小。

分析代码时,请确保您正在比较类似的东西。

vector<int> v(size*size); 

初始化向量中的每个元素,

int arr[size*size]; 

没有。 尝试

int arr[size * size];
memset( arr, 0, size * size );

并再次测量......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM