我和我一起来这里有两个程序,两个程序都完成了同样的任务。它们只是将布尔数组/向量设置为值true。该程序使用矢量 运行需要27秒,而涉及5倍大小的阵列的程序需要不到1秒。我想知道为什么会有这么大的差异的确切原因?是矢量 真的那么低效吗?
使用矢量编程
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
int main(){
const int size = 2000;
time_t start, end;
time(&start);
vector<bool> v(size);
for(int i = 0; i < size; i++){
for(int j = 0; j < size; j++){
v[i] = true;
}
}
time(&end);
cout<<difftime(end, start)<<" seconds."<<endl;
}
运行时 - 27秒
使用数组编程
#include <iostream>
#include <ctime>
using namespace std;
int main(){
const int size = 10000; // 5 times more size
time_t start, end;
time(&start);
bool v[size];
for(int i = 0; i < size; i++){
for(int j = 0; j < size; j++){
v[i] = true;
}
}
time(&end);
cout<<difftime(end, start)<<" seconds."<<endl;
}
运行时 - &lt; 1秒
平台 - Visual Studio 2008 操作系统 - Windows Vista 32位SP 1 处理器Intel(R)Pentium(R)双CPU T2370 @ 1.73GHz 内存(RAM)1.00 GB
由于
阿玛尔
答案 0 :(得分:41)
您正在使用bool的std :: vector,而这不是您认为的那样!
bool的矢量是一个私生子模板专业化,应该永远不存在,实际上每个位存储1个bool。由于屏蔽和移位逻辑,访问它会更复杂,所以肯定会慢一点。
Click here for some info on vector of bool.
此外,您可能正在运行未经优化的构建(几乎可以肯定的是,在您列出的时间内,对于400万次迭代,27秒是令人发指的)。标准模板库非常依赖于优化器来执行内联函数调用和elide temporaries等操作。缺少这种优化会导致bool向量性能下降特别严重,因为它在索引时必须返回一个代理对象,因为你不能取一点地址,所以 operator [] 无法返回参考。
Click here for more info on proxied containers(后半部分是关于布尔的矢量)
此外,许多STL实现都有有用的调试位,这些位不是标准的一部分,可以帮助您捕获错误,但实际上会降低性能。您需要确保在优化版本中禁用这些内容。
一旦打开优化器,进行正确的设置(即没有打开STL调试),并且实际上在两个循环中测试相同的东西,你几乎看不出差异。
我必须让你的循环更大才能在我的机器上进行测试,但这是我的机器上两个bool循环向量的构建,显示了优化器标志对STL代码的影响
$ g++ main.cpp
$ ./a.out
17 seconds.
$ g++ -O2 main.cpp
$ ./a.out
1 seconds.
答案 1 :(得分:2)
答案 2 :(得分:1)
其他答案非常好,但您可以通过this method轻松自行回答。
补充:回应评论,让我告诉你我的意思。我正在运行VC On Windows,但这适用于任何语言/操作系统。我拿了你的第一个程序,并将大小增加到20000,所以它可以运行足够长的时间。然后在它运行的时候,我拍了几张照片。他们都看起来像这样:
std::vector<bool,std::allocator<bool> >::begin() line 93 + 25 bytes
std::vector<bool,std::allocator<bool> >::operator[]() line 132 + 37 bytes
main() line 24 + 12 bytes
mainCRTStartup() line 206 + 25 bytes
KERNEL32! 7c817077()
所以说的是它在第24行的索引操作中花费的时间基本上是所有,并且花费该时间的原因是[]
运算符正在调用begin
运算符。更详细:
main() line 24 + 12 bytes
是这段代码:
for(int j = 0; j < size; j++){
==> v[i] = true;
}
调用:
std::vector<bool,std::allocator<bool> >::operator[]() line 132 + 37 bytes
这是代码(我重新格式化了一下):
reference operator[](size_type _P){
==> return (*(begin() + _P));
}
调用:
std::vector<bool,std::allocator<bool> >::begin() line 93 + 25 bytes
这样做(更详细):
92: iterator begin()
93: {return (_First); }
00402890 push ebp
00402891 mov ebp,esp
00402893 sub esp,44h
00402896 push ebx
00402897 push esi
00402898 push edi
00402899 push ecx
0040289A lea edi,[ebp-44h]
0040289D mov ecx,11h
004028A2 mov eax,0CCCCCCCCh
004028A7 rep stos dword ptr [edi]
004028A9 pop ecx <===============
004028AA mov dword ptr [ebp-4],ecx
004028AD mov eax,dword ptr [ebp-4]
004028B0 mov eax,dword ptr [eax+4]
004028B3 pop edi
004028B4 pop esi
004028B5 pop ebx
004028B6 mov esp,ebp
004028B8 pop ebp
004028B9 ret
它正在做的是在堆栈上写入68个字节的0xCC
(出于某些调试原因),作为获取向量的begin
地址的一部分,作为计算{{{{1}地址的一部分。 1}},在完成作业之前。
它花费的时间比例接近100%,因为它是在拍摄的几个样本中的每一个上进行的。您是否已经猜到这就是几乎所有时间都在做的事情?我不能拥有。
这当然是一个Debug构建。如果您切换到Release版本,但打开调试信息,所有这些函数都会被内联并优化掉,因此它的速度提高了30倍,而且stackshots再次准确地告诉了它正在做什么。
所以 - 人们可以告诉你可能正在做什么,但这显示了如何找出为自己真正做什么
在您的环境中,它无疑会有所不同。
答案 3 :(得分:1)
std::vector<bool>
针对内存消耗而非性能进行了优化。
您可以使用std::vector<int>
欺骗它。那么你不应该有性能缺陷。