......好吧,我得到了奇怪的结果!
我对std::vector
与动态数组的性能感到好奇。看来已经有很多关于这个问题的问题,如果我不经常得到这些“矛盾”的结果,我就不会提到它:vector<int>
比new int[]
更快!我一直认为如果有任何性能差异,它总是喜欢动态数组。这个结果怎么可能?
代码如下:
int numElements = 10000000;
long j = 0;
long k = 0;
vector<int> intVector(numElements);
int* intArray = new int[numElements];
clock_t start, finish;
start = clock();
for (int i = 0; i < numElements; ++i)
intVector[i] = i;
for (int i = 0; i < numElements; ++i)
j += intVector[i];
finish = clock();
cout << "j: " << j << endl;
cout << "Total duration: " << (double) finish - start << " ms." << endl;
// Test Control.
start = clock();
for (int i = 0; i < numElements; ++i)
intArray[i] = i;
for (int i = 0; i < numElements; ++i)
k += intArray[i];
finish = clock();
cout << "k: " << k << endl;
cout << "Total duration: " << (double) finish - start << " ms." << endl;
优化已开启,我在每个开始/结束块中分隔for
循环,以便我可以单独计算数组/向量的初始化时间(在这种情况下,std::vector<int>
和{{1似乎表现相同)。
但是,通过上述代码,new int[]
std::vector<int>
与26-30 ms
的{{1}}不断获胜。
任何人都在关心为什么矢量的表现比动态阵列更好?两者都是在时序循环之前声明的,所以我预计性能大致相同。此外,我使用36-45 ms
和new int[]
尝试了相同的想法并获得了类似的结果,std::vector<int*>
类的性能优于动态数组,因此指针的指针也是如此。
感谢您的帮助。
附录:如果没有优化,new int*[]
会失去一个动态数组的大时间(〜vector
与〜std::vector
),以给出预期的性能差异,但这不是暗示矢量类可以某种方式进行优化,以提供比标准动态数组更好的性能?
答案 0 :(得分:6)
我的猜测是,操作系统在首次访问之前不会分配物理内存。 vector
构造函数将初始化所有元素,因此内存将在您开始计时时分配。阵列内存未初始化(并且可能未分配),因此可能包括分配时间。
尝试将数组初始化更改为int* intArray = new int[numElements]();
以对其元素进行值初始化,并查看是否会更改结果。
答案 1 :(得分:4)
出于所有实际目的,当使用这种方式时,它们的速度完全相同。 vector的operator []通常像[MSVC版本]一样实现:
const_reference operator[](size_type _Pos) const
{ // subscript nonmutable sequence
return (*(_Myfirst + _Pos));
}
......与以下内容相同:
const_reference operator[](size_type _Pos) const
{ // subscript nonmutable sequence
return _Myfirst[_Pos];
}
您的测试基本上只是测试编译器内联代码的能力,而且它似乎在这里做得很好。
至于差异的解释,你得到的任何答案通常都是假设的,而不会看到反汇编。它可能与更好的缓存有关,寄存器更好地用于第一种情况(尝试交换测试的顺序,看看会发生什么),等等。值得注意的是,在测试开始之前,将访问向量的内存。它将所有内容初始化为ctor中的T()。
不幸的是,我们不能简单地编写这样的微观测试,并从中得出一般性的结论。在系统和优化编译器变得如此复杂之前,我们曾经能够做到这一点,但是现在除了现实世界的测试之外,还有太多的变量可以用来做出有意义的结论。
出于同样的原因,我们通常希望任何认真对待性能的人积极地分析他们的代码,因为事情已经变得非常复杂,以至于人们无法正确地确定代码中的瓶颈而没有明显的算法效率低下(我已经我甚至经常看到那些对组装和计算机体系结构有更深刻理解的专业程序员,而当我用剖析器检查他们的假设时,我确实错了。)
答案 2 :(得分:1)
我刚做了这个实验。确实是奇怪的行为,虽然我认为我已经明白了。
再次重复您的代码。那是......
benchmark vector
benchmark array
benchmark vector
benchmark array
你会注意到你第二次会得到不同的数字。我猜?页面错误。由于某种原因,向量不会导致页面错误,而数组方法会导致页面错误。页面加载后,两者将以大致相同的速度运行(即:第二次发生的情况)。到目前为止,有谁知道如何在一个过程中打印页面错误的数量?