Std::设置快与慢,是怎么回事
std::set fast and slow, what is going on?
我发现std::set有一个奇怪的行为。
代码如下:
#include <cstdio>
#include <windows.h>
#include <stdlib.h>
#include <vector>
#include <set>
using namespace std;
int main(int argc, char *argv[])
{
set<int> b[100];
for (int o=0; o<10; o++)
{
int tt = GetTickCount();
for (int i=0; i<5000000; i++)
{
b[o].insert(i);
}
tt = GetTickCount() - tt;
b[o].clear();
printf("%dn", tt);
}
return 0;
}
我用的是Windows XP。
下面是有趣的部分:第一次打印时间约为3500毫秒,而接下来的所有打印时间都超过9000毫秒!为什么会这样呢?
哦,这只发生在发布版本(-O2优化)。
这在Linux上不会发生(在修改代码以在那里编译之后)。
还有一件事:当我用Intel VTune运行它时,它总是需要大约3000毫秒,所以它应该是这样的。
更新:下面是一些新代码:
#include <cstdio>
#include <windows.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
const int count = 10000000;
int **a = new int*[count];
for (int o=0; o<10; o++)
{
int ttt = GetTickCount();
for (int i=0; i<count; i++)
{
a[i] = new int;
*a[i] = i;
}
int ttt2 = GetTickCount();
for (int i=0; i<count; i++)
{
int r1 = rand() * 10000 + rand();
int r2 = rand() * 10000 + rand();
r1 = r1%count;
r2 = r2%count;
int *e = a[r1];
a[r1] = a[r2];
a[r2] = e;
}
int ttt3 = GetTickCount();
for (int i=0; i<count; i++)
{
delete a[i];
}
int ttt4 = GetTickCount();
printf("%d %dn", ttt2-ttt, ttt4-ttt3);
}
return 0;
}
这是同样的问题。实际情况是,我分配了很多很多小对象,然后以随机顺序删除它们——这与std::set中的情况类似。这就是Windows内存管理问题。它不能很好地处理许多小的分配和删除。
我不能确切地解释为什么会发生这种情况,但我可以提出一个解决方案。当我在调试器下运行发布构建(使用F5
)时,我已经能够在我的PC上复制这一点。当我从命令行或Ctrl-F5
运行构建时,我没有得到那种行为。
这与在调试器下启动时默认打开的调试堆有关。这里有非常详细的描述。要防止这种情况发生
- 从命令行或
Ctrl-F5
运行(Debug -> Start Without Debugging) 进入Project -> Properties -> Debugging -> Environment,添加
_NO_DEBUG_HEAP=1
。如果我不得不猜测,我会说这与Windows/VS运行时内存分配跟踪的实现有关。可能是一些内部列表填满了,重新分配了,或者发生了其他事情。
我认为std::set
是作为二叉搜索树实现的。由于每次都将i增加1,因此实际上为这种类型的数据结构创建了一个对抗性(最坏情况)场景(几乎每次插入都需要重新平衡树)。
同样,它有5000万次插入,所以预计会有一些时间,尽管我不认为它会是5毫秒。
此外,我会在您打印时间后执行您的"清除",因为我不明白您为什么要对插入和删除项进行基准测试。
相关文章:
- 使用递归的数组的最小值.这是怎么回事
- 我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
- 我使用 OpenMP 的线程越多,执行时间就越长,这是怎么回事?
- 绕道重铸瓷砖层是怎么回事
- 架 (U+67B6) 与en_US不符.UTF-8.这是怎么回事?
- R 中的算术在数字上比整数更快。这是怎么回事?
- 我的代码运行良好,但现在当尝试将其制作成模板时,我遇到了许多看似无关的错误。这是怎么回事?
- 在变量名后声明带有 () 的非内部类型与不使用变量名的行为不同。即 std::map<int,char>x(); - 这是怎么回事?
- 弄清楚这段代码是怎么回事(递归下降案例研究)
- 分配器密集和稀疏是怎么回事?
- 传递引用C++,指针的向量.这是怎么回事?
- __vector_base_common是怎么回事?
- (对象)不命名类型.怎么回事
- 变量已在 .obj 中定义;这是怎么回事?
- Sublime上的EasyClangComplete是怎么回事?
- 重复输出的类型是怎么回事,它如何区分迭代次数和 Ascii 代码?
- 标准::地图使用.这是怎么回事?核心转储?我做得不正确?
- llvm libcxx的源代码是怎么回事?
- 这一行是怎么回事: istringstream is( line );
- Std::设置快与慢,是怎么回事