使用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;
}
答案 0 :(得分:21)
您的数组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上进行:
使用Visual Studio 2008中的调试设置(无优化,运行时检查和调试运行时),矢量测试花费了920 ms,而阵列测试则为0 ms。
在vector::operator[]
中花费了98,48%的总时间,即确实花费在运行时检查上的时间。
完全优化后,矢量测试需要56 ms(带有原始条目数的十分之一),而阵列则为0 ms。
vector ctor需要61.72%的总应用程序运行时间。
所以我猜每个人都是正确的,这取决于所使用的编译器设置。 OP的时序表明优化的构建或STL没有运行时检查。
与往常一样,士气是:配置文件优先,优化第二。
答案 1 :(得分:9)
如果您使用Microsoft编译器进行编译,为了使其公平比较,您需要通过定义_SECURE_SCL = 0和_HAS_ITERATOR_DEBUGGING = 0来关闭迭代器安全检查和迭代器调试。
其次,您使用的构造函数将每个向量值初始化为零,并且在填充之前您不会将数组memset为零。所以你要遍历矢量两次。
尝试:
vector<int> v;
v.reserve(size*size);
答案 2 :(得分:3)
将作业更改为例如。 arr[i*size+j] = i*j
,或其他一些非常量表达式。我认为编译器会优化整个循环,因为从不使用赋值,或者用一些预先计算的值替换数组,因此循环甚至不会被执行而且你得到0毫秒。
将1更改为i*j
后,i
获取向量和数组的相同时序,除非将-O1
标志传递给gcc,然后在两种情况下都得到0毫秒。
所以,首先,仔细检查你的循环是否实际执行。
答案 3 :(得分:3)
为了得到公平的比较,我认为以下内容应该是合适的:
#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!
编辑:更正了代码以强制矢量销毁包含在时间测量中。
答案 4 :(得分:2)
您可能正在使用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);
答案 5 :(得分:1)
两件事。一,运算符[]对于向量来说要慢得多。二,当你一次添加一个元素时,大多数实现中的向量都会表现得很奇怪。我并不仅仅意味着它会分配更多的内存,但它有时会做一些真正奇怪的事情。
第一个是主要问题。对于仅仅百万字节,甚至重新分配内存十几次不应该花费很长时间(它不会在每个添加的元素上执行)。
在我的实验中,预分配并没有太大改变其缓慢程度。当内容是实际的对象时,如果你尝试做一些简单的事情,比如排序它,它基本上就会停止。
结论,不要将stl或mfc向量用于任何大型或计算量较大的载体。它们执行得很慢/很慢并导致大量内存碎片。
答案 6 :(得分:0)
当你声明数组时,它存在于堆栈中(或静态内存区域),它非常快,但不能增加它的大小。
当您声明向量时,它会分配动态内存,它不是那么快,但在内存分配方面更灵活,因此您可以更改大小而不是将其标注为最大大小。
答案 7 :(得分:0)
在分析代码时,请确保您正在比较类似的东西。
vector<int> v(size*size);
初始化向量中的每个元素
int arr[size*size];
没有。尝试
int arr[size * size];
memset( arr, 0, size * size );
再次测量......