简体   繁体   English

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

[英]std::set fast and slow, what is going on?

I've come up across a strange behaviour of std::set. 我遇到了std :: set的奇怪行为。

Here is the code: 这是代码:

#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;
}

I'm running on Windows XP. 我在Windows XP上运行。

Here is the interesting part: this first printed time is about 3500 ms, while all next are over 9000 ms! 这是有趣的部分:第一次打印时间约为3500毫秒,而接下来的时间都超过9000毫秒! Why is that happening? 为什么会这样?

Oh, and this only happens on release version (-O2 optimization). 哦,这只发布在发布版本(-O2优化)。

It doesn't happen on Linux (after changing code to compile there). 它不会发生在Linux上(在更改代码后进行编译)。

One more thing: when I run it while profiling with Intel VTune it always takes about 3000 ms, so it's the way it should be. 还有一件事:当我使用英特尔VTune进行性能分析时运行它总是需要大约3000毫秒,所以它应该是这样的。

UPDATE: Here is some new code: 更新:这是一些新代码:

#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;
}

This is the same problem. 这是同样的问题。 What happens is I allocate many many small objects and then delete them in random order - so it is similar to how it looks in std::set. 发生的事情是我分配了许多小对象,然后以随机顺序删除它们 - 所以它类似于它在std :: set中的样子。 So this is Windows memory management problem. 所以这是Windows内存管理问题。 It can't really handle well many small allocs and deletes. 它无法真正处理很多小的alloc和delete。

I cannot explain exactly why this is happening but I could propose a solution. 我无法解释为什么会发生这种情况,但我可以提出一个解决方案。 I've been able to reproduce this on my PC when I run the release build under the debugger (with F5 ). 当我在调试器(使用F5 )下运行发布版本时,我已经能够在我的PC上重现这一点。 When I run the build from the command line or with Ctrl-F5 I don't get that kind of behavior. 当我从命令行或使用Ctrl-F5运行构建时,我没有得到那种行为。

This has something to do with the debug heap which is on by default when you launch under the debugger. 这与调试堆有关,在调试器下启动时默认启用调试堆。 It's described in great detail here . 这里详细介绍了它 To prevent this from happening either 为了防止这种情况发生

  1. Run from the command line or with Ctrl-F5 (Debug -> Start Without Debugging). 从命令行或使用Ctrl-F5 (Debug - > Start Without Debugging)。
  2. Go to Project -> Properties -> Debugging -> Environment and add _NO_DEBUG_HEAP=1 . 转到项目 - >属性 - >调试 - >环境并添加_NO_DEBUG_HEAP=1

If I had to guess I would say that it has something to do with the implementation of the memory allocation tracking in Windows/VS runtime. 如果我不得不猜测我会说它与Windows / VS运行时中内存分配跟踪的实现有关。 Probably some internal lists fill up and reallocate or something else along these lines. 可能一些内部列表会填充并重新分配或沿着这些行添加其他内容。

I think std::set is implemented as a binary search tree. 我认为std::set是作为二叉搜索树实现的。 Since you are increasing i by 1 every time you are essentially creating an adversarial (worst case) scenario for this type of datastructure (rebalancing of the tree is required on almost every insert). 因为每次实际上为这种类型的数据结构创建一个对抗(最坏情况)场景时,你将i增加1(几乎每个插入都需要重新平衡树)。

Also, it is 50 million inserts, so some time is expected, though I wouldn't think it would be 5 ms. 此外,它是5000万插入,所以有一段时间,但我不认为它将是5毫秒。

Also, I would do your "clear" after you print your time, as I don't see the reason you would benchmark both inserting and removing items. 此外,打印您的时间之后,我会“清除”,因为我没有看到您对插入和移除项目进行基准测试的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM