【问题标题】:std::queue destructor is slow as hell, bug? [closed]std::queue 析构函数太慢了,bug? [关闭]
【发布时间】:2016-03-17 07:52:52
【问题描述】:

为什么std::queue 中的析构函数非常慢?看看我的例子:

void test()
{
    int total = 17173512;
    std::queue<int> q;
    for(int i = 0; i < total; i++)
        q.push(i); //Push is very fast.

    std::cout<<"Done"<<std::endl; //Less than a second.
}

test();
std::cout<<"Done"<<std::endl; //This takes several minutes!!

std::vector 中的析构函数非常快...

更新: 我的编译器/IDE 是 Visual Studio 2012 Visual C++。

int main(int argc, char **argv)
{
    int total = 17173512;
    std::queue<int> q;
    for(int i = 0; i < total; i++)
        q.push(i);

    std::cout<<"Done0"<<std::endl; //This takes less than a second.

    while(!q.empty())
        q.pop();

 //This takes less than a second. Memory should be deallocated here!
    std::cout<<"Done1"<<std::endl;

    //Waiting forever, i.e. deallocating(HERE??) memory EXTREMELY SLOWLY.
   //I can see how the memory is being deallocated here in windows task manager!
        return 0;
}

带矢量:

int main(int argc, char **argv)
{
    int total = 17173512;
    std::vector<int> q(total);
    for(int i = 0; i < total; i++)
        q[i] = 2000;

    std::cout<<"Done"<<std::endl;

    return 0; //Extremely fast.
}

更新 2:

现在一切都解决了!我卸载了 Visual Studio 2012 + Visual C++。我已经安装了 Visual Studio Community 2015,一切都比预期的要快得多!

【问题讨论】:

  • 有趣。你能粘贴一个完整的程序来演示这个吗?
  • 您是否在打开优化的情况下进行编译?另外,您使用的是哪个 c++ 实现?
  • 即使使用-O0,对我来说也只需不到一秒钟。
  • 您必须向我们提供有关编译器/系统/实现和上下文的更多信息。在我的 2009 macbook pro 中使用 clang 并使用 -O0 我可以在 1486 毫秒内运行您的代码,对于如此庞大的队列来说这根本不是很多。使用 -O3 我得到 150 毫秒。
  • 另外,你应该和std::deque&lt;int&gt;比较,这是队列内部使用的。

标签: c++ performance queue destructor


【解决方案1】:

我已经用这个代码来测量了:

int main(){
    auto test = [](){
        auto start = std::chrono::system_clock::now();
        int total = 17173512;
        std::queue<int> q;
        for (int i = 0; i < total; i++){
            q.push(i); //Push is very fast.
        }
        auto end = std::chrono::system_clock::now();
        return end - start;
    };

    auto start = std::chrono::system_clock::now();

    auto pushing_time = test();

    auto end = std::chrono::system_clock::now();
    auto deleting_time = (end - start) - pushing_time;

    std::cout << "Pushing Time:" << pushing_time.count() << '\n';
    std::cout << "Deleting Time:" << deleting_time.count() << '\n';
    return 0;
}

环境:

  • 英特尔 i7-4510U @ 2.00 GHz
  • Windows 8.1
  • MSVS 2013

结果:

发布模式,\O2,附加到VS:

推送时间:71403190

删除时间:5293067027

发布模式,\O2,未附加到VS:

推送时间:3743267

删除时间:1741230

所以从结果来看,我怀疑您是否将它附加到某个 IDE 上运行。

【讨论】:

  • 查看我更新的问题!
  • +1 表示测量工作量。结果在 ideone 上也是不利的,虽然没有 MSVC2013 大:对于队列,删除时间是 19.011.638,而对于向量,它是 4.392.646,所以大约慢了 5 倍。
  • 在英特尔 i7 2,9 GHz、win10 和最新的 MSVC2015 版本中,队列仍然为 2.457.842,向量为 63.422。这慢了 38 倍。使用链表是 7.829.505
【解决方案2】:

当一个包含 n 个元素的向量被销毁时,这 n 个元素被销毁,然后内存在 1 个操作(连续块)中被释放。

对于要销毁的队列,内存在 n 次操作中被释放,并且内存管理系统必须管理这 n 个空闲块(例如在链表中)。因此,内存管理会显着影响性能

【讨论】:

  • std::queue 默认使用std::deque,它没有链表那么糟糕。无论如何,几分钟是荒谬的。
  • @T.C.确实如此。以 Humam Helfawi 的测量代码为例,在 MSVC2015 中,链表肯定更差(比队列慢 3 倍),但队列的销毁速度比向量慢 38 倍。我怀疑内存释放的实现非常糟糕
【解决方案3】:

Christophe 对容器类型的看法通常是正确的,但这里的问题与容器类型无关。我们希望内存分配和释放几乎相等。我在调试和释放模式下分析了MSVC2010中的代码。分析表明,删除操作比新建操作更耗时。删除操作好像包含了一些额外的操作,但具体我不是很清楚。

【讨论】:

    猜你喜欢
    • 2016-07-20
    • 1970-01-01
    • 2022-01-11
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    相关资源
    最近更新 更多