std ::设置得快又慢,发生什么事了?

时间:2011-11-16 11:44:24

标签: c++ windows stl set

我遇到了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("%d\n", tt);
    }

    return 0;
}

我在Windows XP上运行。

这是有趣的部分: 第一次打印时间约为3500毫秒,而接下来的时间都超过9000毫秒! 为什么会这样?

哦,这只发布在发布版本(-O2优化)上。

在Linux上不会发生这种情况(更改代码后再编译)。

还有一件事:当我使用英特尔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 %d\n", ttt2-ttt, ttt4-ttt3);
}

return 0;
}

这是同样的问题。 发生的事情是我分配了许多小对象,然后以随机顺序删除它们 - 所以它类似于它在std :: set中的样子。 所以这是Windows内存管理问题。它无法真正处理很多小的分配和删除。

2 个答案:

答案 0 :(得分:6)

我无法解释为什么会发生这种情况,但我可以提出解决方案。当我在调试器下运行发布版本时(F5),我已经能够在我的PC上重现这一点。当我从命令行或Ctrl-F5运行构建时,我没有那种行为。

这与调试堆有关,在调试器下启动时默认启用调试堆。它的描述非常详细here。为了防止这种情况发生

  1. 从命令行或Ctrl-F5运行(调试 - &gt;启动无调试)。
  2. 转到项目 - &gt;属性 - &gt;调试 - &gt;环境并添加_NO_DEBUG_HEAP=1
  3. 如果我不得不猜测我会说它与Windows / VS运行时中内存分配跟踪的实现有关。可能一些内部列表会填满并重新分配这些行中的其他内容。

答案 1 :(得分:0)

我认为std::set是作为二叉搜索树实现的。因为每次实际上为这种类型的数据结构创建一个对抗(最坏情况)场景时,你将i增加1(几乎每个插入都需要重新平衡树)。

此外,它有5000万个插页,所以预计会有一段时间,但我认为它不会是5毫秒。

此外,在您打印时间后,我会“清除”,因为我没有看到您插入和删除项目的基准。