【发布时间】:2014-03-16 00:00:33
【问题描述】:
在编写一个处理大量元素(约 100k)的程序时,我注意到 std::list 和 QList 之间有一个奇怪的区别。 一开始我使用了一个std::vector,它表现不错。但是因为程序经常需要在向量中的随机位置插入元素,所以我切换到 std::list,当迭代器位于所需位置时,它的插入时间是恒定的。
问题是,std::list 在 insert() 和 push_back() 方法中的表现都比 std::vector 差。 测量将 100 个连续元素添加到我得到的 100k 个元素的列表中:
- ~25ms 用于 std::vector(最坏的情况是在开头添加)
- std::list 超过 600 毫秒(!)(任何位置,即使使用 push_back() 或 insert(list.begin())。
请注意,插入元素的时间不包括迭代器到达位置的时间。
我知道列表的性能问题是由于列表导致缓存未命中,但这似乎超出了缓存未命中的限制。 此外,插入元素(具有 5 个恒定长度变量的简单结构)的时间随着列表的大小而增加。即使是获取列表大小的操作也需要更多时间。 这与列表的两个操作所保证的时间复杂度完全相反:constant。
见:Here
出于好奇,从 std::list 更改为 QList 和 viola:插入时间是恒定的,介于 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";
结果:经过:662ms
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";
结果:经过:1ms
std::vector:
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";
结果:经过:27ms
那么,为什么 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;
【问题讨论】:
-
请提供SSCCE。
-
没有上下文 (SSCCE),我们只能猜测发生了什么。例如,我可以猜测,
QList可能只存储一个指针(取决于元素的类型),而list和vector按值存储。此外,我可以猜测,list没有保留“空闲列表”,因此必须为每个插入的元素分配。 -
您能否展示足够多的代码以查看所有相关变量的声明,尤其是
ElementList、actIterator和lineChange? -
另外,请注意 QList 不是链表。来自docs:“在内部,QList
表示为指向 T 类型项的指针数组。如果 T 本身是指针类型或不大于指针的基本类型,或者 T 是Qt 的共享类,然后 QList 将项目直接存储在指针数组中。” -
您提到 size() 表现不佳 - 这可能是由于 gcc 在这种情况下没有维护新标准。见 - stackoverflow.com/questions/19154205/…
标签: performance c++11 stdvector qlist stdlist