std :: vector,QList和std :: list之间存在奇怪的(巨大的)性能差异

时间:2014-03-16 00:00:33

标签: performance c++11 stdvector qlist stdlist

在编写处理相对大量元素(~100k)的程序时,我注意到 std :: list QList 之间存在奇怪的区别。 起初我使用了 std :: vector ,效果很好。但是因为程序经常需要在向量中的随机位置插入元素,所以当迭代器处于所需位置时,我切换到 std :: list ,它有一个恒定的插入时间。 / p>

问题是,std :: list的执行方式比使用insert()和push_back()方法的std :: vector更差。 测量为将100个连续元素添加到具有100k元素的列表中:

  • ~stms :: vector的25ms(最开始时添加的情况)
  • 对于std :: list超过600ms(!)(任何位置,即使使用push_back()或insert(list.begin())。

请注意,插入元素的时间不包括使用迭代器到达位置的时间。

我知道列表的性能问题,因为列表导致了缓存缺失,但这似乎远远超出了缓存未命中的限制。 插入元素(具有5个常量长度变量的简单结构)的时间也随着列表的大小而增加。即使获得列表大小的操作也需要更多时间。 这与列表的两个操作保证的时间复杂性形成鲜明对比:常量

请参阅:Here

出于好奇,从 std :: list 更改为 QList 和中提琴:插入时间是恒定的,介于0ms和1ms之间。

以下是用于衡量插入时间的代码。

  

两个时间点之间不执行任何其他操作:错误:使用size()方法

的std ::列表:

    QTime time;
    time.start();

    for (int a = 1; a <= lineChange; a++)
    {
        listData.insert(listIterator, newElement); 
    }        
    int elapsed = time.restart();
    qDebug() << "elapsed: " << elapsed << "ms";

结果:已过去:662毫秒

的QList:

    QTime time;
    time.start();

    for (int a = 1; a <= lineChange; a++)
    {
        QListData.insert(iteratorPos, newElement);
        position++;
    } 

    int elapsed = time.restart();
    qDebug() << "elapsed: " << elapsed << "ms";

结果:已过去:1毫秒

的std ::矢量:

    QTime time;
    time.start();

    for (int a = 1; a <= lineChange; a++)
    {
        vectorData.insert(vectorIterator, newElement);

        /*update of the iterator when it was 
        invalidated due to resize of the vector*/
    }    

    int elapsed = time.restart();
    qDebug() << "elapsed: " << elapsed << "ms";

结果:已过去:27毫秒

那么,为什么QList和std :: list之间存在如此巨大的差异? 或者更好:为什么 std :: list 的性能如此糟糕?

作为附带信息:我在Linux(Mint)下使用带有gcc的QtEditor,标志设置为c ++ 11

编辑:

数据类型和声明:

typedef struct TOKELEMENT {
    unsigned int column;
    unsigned int lenght;
    unsigned int tType;
    std::string value;
} tokElement;

// the three lists
std::vector<okElement> vectorData;
std::list<tokElement> listData;
QList<tokElement> QListData;

tokElement newElement;

unsigned int iteratorPos;
std::vector<std::vector<tokElement> >::iterator vectorIterator;
std::list<std::vector<tokElement> >::iterator listIterator;

//lineChange is an unsigned int, given as function parameter
unsigned int lineChange;

1 个答案:

答案 0 :(得分:3)

与我在问题中提到的内容(对我的耻辱)相反,我在 for-loop 中另外检查了 std :: list 的大小确定是否在列表中使用insert()或push_back()。 由于该函数不具有O(1)但O(n)的时间复杂度,因此这大大减慢了整个插入。感谢 Leeor 指出这一点。

将此检查移出 for-loop 之后,std :: list按照预期执行,甚至比QList更快。