std::queue; >::size() 在 O(n) 内很慢?

发布于 2024-12-10 20:06:50 字数 2399 浏览 0 评论 0 原文

我的代码使用队列时遇到了意外的性能行为。我意识到当队列中有更多元素时,性能会下降。事实证明,原因是使用了 size() 方法。以下是显示问题的一些代码:

#include <queue>
#include <list>
#include <iostream>

#include "Stopwatch.h"

using namespace std;

struct BigStruct
{
    int x[100];
};
int main()
{
    CStopwatch queueTestSw;

    typedef BigStruct QueueElementType;
    typedef std::queue<QueueElementType, std::list<QueueElementType> > QueueType;
    //typedef std::queue<QueueElementType > QueueType; //no surprise, this queue is fast and constant
    QueueType m_queue;

    for (int i=0;i<22000;i++)
        m_queue.push(QueueElementType());
    CStopwatch sw;
    sw.Start();
    int dummy;
    while (!m_queue.empty())
    {
        //remove 1000 elements:
        for (int i=0;i<1000;i++)
        {
            m_queue.pop();
        }
        //call size() 1000 times and see how long it takes
        sw = CStopwatch();
        sw.Start();
        for (int i=0;i<1000;i++)
        {   
            if (m_queue.size() == 123456)
            {
                dummy++;
            }
        }
        std::cout << m_queue.size() << " items left. time: " << sw.GetElapsedTimeInSeconds() << std::endl;  
    }   
    return dummy;


}

其中 CStopwatch 是一个使用 clock_gettime(CLOCK_REALTIME, ..) 的类。结果是:

21000 items left. time: 1.08725
20000 items left. time: 0.968897
19000 items left. time: 0.818259
18000 items left. time: 0.71495
17000 items left. time: 0.583725
16000 items left. time: 0.497451
15000 items left. time: 0.422712
14000 items left. time: 0.352949
13000 items left. time: 0.30133
12000 items left. time: 0.227588
11000 items left. time: 0.178617
10000 items left. time: 0.124512
9000 items left. time: 0.0893425
8000 items left. time: 0.0639174
7000 items left. time: 0.0476441
6000 items left. time: 0.033177
5000 items left. time: 0.0276136
4000 items left. time: 0.022112
3000 items left. time: 0.0163013
2000 items left. time: 0.0101932
1000 items left. time: 0.00506138

这似乎与 http://www.cplusplus.com/reference/stl/queue/size 相矛盾/

复杂性:恒定。

如果结构更大,问题会更严重。我正在使用海湾合作委员会4.3.2。

你能解释一下吗?有没有办法使用列表来解决这个问题?

(请注意,我需要使用列表作为队列的底层容器,因为我需要恒定的时间插入复杂性。)

I experienced unexpected performance behavior of my code which uses a queue. I realized that performance degraded when more elements were in the queue. It turned out that usage of the size() method was the reason. Here is some code that shows the problem:

#include <queue>
#include <list>
#include <iostream>

#include "Stopwatch.h"

using namespace std;

struct BigStruct
{
    int x[100];
};
int main()
{
    CStopwatch queueTestSw;

    typedef BigStruct QueueElementType;
    typedef std::queue<QueueElementType, std::list<QueueElementType> > QueueType;
    //typedef std::queue<QueueElementType > QueueType; //no surprise, this queue is fast and constant
    QueueType m_queue;

    for (int i=0;i<22000;i++)
        m_queue.push(QueueElementType());
    CStopwatch sw;
    sw.Start();
    int dummy;
    while (!m_queue.empty())
    {
        //remove 1000 elements:
        for (int i=0;i<1000;i++)
        {
            m_queue.pop();
        }
        //call size() 1000 times and see how long it takes
        sw = CStopwatch();
        sw.Start();
        for (int i=0;i<1000;i++)
        {   
            if (m_queue.size() == 123456)
            {
                dummy++;
            }
        }
        std::cout << m_queue.size() << " items left. time: " << sw.GetElapsedTimeInSeconds() << std::endl;  
    }   
    return dummy;


}

Where CStopwatch is a class which uses clock_gettime(CLOCK_REALTIME, ..). The result is:

21000 items left. time: 1.08725
20000 items left. time: 0.968897
19000 items left. time: 0.818259
18000 items left. time: 0.71495
17000 items left. time: 0.583725
16000 items left. time: 0.497451
15000 items left. time: 0.422712
14000 items left. time: 0.352949
13000 items left. time: 0.30133
12000 items left. time: 0.227588
11000 items left. time: 0.178617
10000 items left. time: 0.124512
9000 items left. time: 0.0893425
8000 items left. time: 0.0639174
7000 items left. time: 0.0476441
6000 items left. time: 0.033177
5000 items left. time: 0.0276136
4000 items left. time: 0.022112
3000 items left. time: 0.0163013
2000 items left. time: 0.0101932
1000 items left. time: 0.00506138

This seems to contradict http://www.cplusplus.com/reference/stl/queue/size/:

Complexity: Constant.

The problem is worse if the struct is bigger. I am using GCC 4.3.2.

Can you explain this? Is there a way to solve this using the list?

(Please note that I need to use the list as underlying container of the queue because I need constant time insertion complexity.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

べ映画 2024-12-17 20:06:50

queue 是一个容器适配器,因此您必须了解复杂性描述可能仅指适配器本身所做的工作(这确实是不变的,即只是传递调用到底层容器)。

例如,请参阅此参考size() 调用底层容器的 size() 函数。对于列表,在 C++98/03 中复杂度为 O(n),在 C++11 中复杂度为 O(1)。

queue is a container adaptor, so you have to understand that the complexity descriptions may refer only to the work the adaptor does itself (which is indeed constant, namely just passing the call through to the underlying container).

For example, see this reference: size() calls the underlying container's size() function. For a list, this has complexity O(n) in C++98/03, and O(1) in C++11.

眼眸 2024-12-17 20:06:50

您的 queue 使用 list 容器,而不是默认的 deque

typedef std::queue<QueueElementType, std::list<QueueElementType> > QueueType;

大小需要 O(n ),因为这是 C++11 之前的 list 容器的完全有效的实现。该标准的先前版本不保证列表的 size 成员函数的复杂性。

如果您将代码更改为:

typedef std::queue<QueueElementType, std::deque<QueueElementType> > QueueType;

您将看到您想要的行为(O(1) 大小复杂度)。

You're your queue to use a list container, instead of the deque default:

typedef std::queue<QueueElementType, std::list<QueueElementType> > QueueType;

You shouldn't be surprised that size takes O(n), since that's a perfectly valid implementation of the list container pre C++11. The previous version of the standard did not guarantee the complexity of the size member function for lists.

If you change your code to:

typedef std::queue<QueueElementType, std::deque<QueueElementType> > QueueType;

You will see the behavior you want (O(1) size complexity).

水水月牙 2024-12-17 20:06:50

添加到迈克尔的答案:您使用 std::list 作为队列容器,因此 size() 方法取决于您的 std::list 大小实现。如果您在同一个网站上查找,您会发现 http://www.cplusplus.com /reference/stl/list/size/ 并且复杂性在某些实现上是恒定的,而在其他实现上是线性的。如果您需要恒定的插入和大小,那么您需要不同的数据结构或更好的 std::list 实现。

Adding to Michael's answer: You're using std::list as your queue container, so the size() method depends on your std::list implementation of size. If you look up on the same website, you find http://www.cplusplus.com/reference/stl/list/size/ and the complexity is constant on some implementations and linear on others. If you need constant insertion and size, then you need a different data structure or a better std::list implementation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文