[英]Why std::vector<uint8_t>::insert works 5 times faster than std::copy with MSVC 2015 compiler?
[英]Why is std::vector::operator[] 5 to 10 times faster than std::vector::at()?
在程序优化期间,尝试优化迭代遍历向量的循环,我发现以下事实::: std :: vector :: at()比operator []快得多!
在发布和调试版本(VS2008 x86)中,operator []比at()快5到10倍 。
在网上读了一下让我意识到at()有边界检查。 好的,但是,将操作放慢了10倍?!
有什么理由吗? 我的意思是,边界检查是一个简单的数字比较,还是我错过了什么?
问题是这种性能受损的真正原因是什么?
更进一步, 有没有办法让它更快 ?
我肯定会在其他代码部分(我已经有自定义边界检查!)中将所有at()调用与[]交换。
概念证明:
#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <conio.h>
#include <vector>
#define ELEMENTS_IN_VECTOR 1000000
int main()
{
__int64 freq, start, end, diff_Result;
if(!::QueryPerformanceFrequency((LARGE_INTEGER*)&freq))
throw "Not supported!";
freq /= 1000000; // microseconds!
::std::vector<int> vec;
vec.reserve(ELEMENTS_IN_VECTOR);
for(int i = 0; i < ELEMENTS_IN_VECTOR; i++)
vec.push_back(i);
int xyz = 0;
printf("Press any key to start!");
_getch();
printf(" Running speed test..\n");
{ // at()
::QueryPerformanceCounter((LARGE_INTEGER*)&start);
for(int i = 0; i < ELEMENTS_IN_VECTOR; i++)
xyz += vec.at(i);
::QueryPerformanceCounter((LARGE_INTEGER*)&end);
diff_Result = (end - start) / freq;
}
printf("Result\t\t: %u\n\n", diff_Result);
printf("Press any key to start!");
_getch();
printf(" Running speed test..\n");
{ // operator []
::QueryPerformanceCounter((LARGE_INTEGER*)&start);
for(int i = 0; i < ELEMENTS_IN_VECTOR; i++)
xyz -= vec[i];
::QueryPerformanceCounter((LARGE_INTEGER*)&end);
diff_Result = (end - start) / freq;
}
printf("Result\t\t: %u\n", diff_Result);
_getch();
return xyz;
}
编辑:
现在该值被赋予“xyz”,因此编译器不会“擦除”它。
原因是可以使用单个处理器指令完成未经检查的访问。 检查访问还必须从内存加载大小,将其与索引进行比较,并(假设它在范围内)跳过条件分支到错误处理程序。 可能会有更多的事情来处理抛出异常的可能性。 这将慢很多倍,这正是您有两个选择的原因。
如果您可以在没有运行时检查的情况下证明索引在范围内,则使用operator[]
。 否则,请使用at()
,或在访问前添加自己的检查。 operator[]
应该或多或少尽可能快,但如果索引无效则会乱码。
我在我的机器上运行了测试代码:
在未优化的调试版本中,两个循环之间的差异是微不足道的。
在优化的发布版本中,第二个for循环完全被优化(对operator[]
的调用可能是内联的,优化器可以看到循环什么也不做,可以删除整个循环)。
如果我改变循环的主体来做一些实际的工作,例如, vec.at(i)++;
和vec[i]++;
分别是两个循环之间的差异是微不足道的。
我看不到你看到的五到十倍的性能差异。
你没有对返回值做任何事情,所以如果编译器内联这些函数,它可以完全优化它们。 或许它可以完全优化掉下标( []
)版本。 从性能测量的角度来看,没有优化的运行是没有用的,你需要的是一些简单但有用的程序来运用这些功能,这样它们就不会被优化掉。 例如,您可以随机播放矢量(随机交换50000对元素)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.