我试图将一些使用C风格的整数向量的代码重构为QVector(因为其余代码使用Qt)。
在我这样做之前,我进行了性能测试,以检查这种变化有多糟糕。
我使用此代码:
#include <QVector>
#include <vector>
#include <cstdio>
#include <ctime>
void test1(int MAX_ELEMENTS, int TIMES) {
int vec[MAX_ELEMENTS];
int nelems = 0;
for (int j=0; j<TIMES; j++) {
nelems = MAX_ELEMENTS;
for (int i=0; i<MAX_ELEMENTS; i++)
vec[i] = 2;
}
printf("Vec[0] = %d\n", vec[0]);
}
void test2(int MAX_ELEMENTS, int TIMES) {
std::vector<int> vec;
vec.reserve(MAX_ELEMENTS);
for (int j=0; j<TIMES; j++) {
vec.clear();
for (int i=0; i<MAX_ELEMENTS; i++)
vec.push_back(2);
}
printf("Vec[0] = %d\n", vec[0]);
}
void test3(int MAX_ELEMENTS, int TIMES) {
QVector<int> vec;
vec.reserve(MAX_ELEMENTS);
for (int j=0; j<TIMES; j++) {
vec.clear();
for (int i=0; i<MAX_ELEMENTS; i++)
vec.push_back(2);
}
printf("Vec[0] = %d\n", vec[0]);
}
void test4(int MAX_ELEMENTS, int TIMES) {
QVector<int> vec;
vec.reserve(MAX_ELEMENTS);
for (int j=0; j<TIMES; j++) {
vec.resize(MAX_ELEMENTS);
for (int i=0; i<MAX_ELEMENTS; i++)
vec[i] = 2;
}
printf("Vec[0] = %d\n", vec[0]);
}
double measureExecutionTime(void (*func)(int, int)) {
const int MAX_ELEMENTS=30000;
const int TIMES=2000000;
clock_t begin, end;
begin = clock();
(*func)(MAX_ELEMENTS, TIMES);
end = clock();
return (double)(end - begin) / CLOCKS_PER_SEC;
}
int main() {
double time_spent;
time_spent = measureExecutionTime(test1);
printf("Test 1 (plain c): %lf\n", time_spent);
time_spent = measureExecutionTime(test2);
printf("Test 2 (std::vector): %lf\n", time_spent);
time_spent = measureExecutionTime(test3);
printf("Test 3 (QVector clear): %lf\n", time_spent);
time_spent = measureExecutionTime(test4);
printf("Test 4 (QVector resize): %lf\n", time_spent);
return 0;
}
结果是:
Vec[0] = 2
Test 1 (plain c): 16.130129
Vec[0] = 2
Test 2 (std::vector): 92.719583
Vec[0] = 2
Test 3 (QVector clear): 109.882463
Vec[0] = 2
Test 4 (QVector resize): 46.261172
为了提高QVector性能,有何不同的想法? 该向量从0填充到每秒几次的新大小(它用于时间表调度软件)。
Qt版本:5.7.1(+ dsfg1,来自Debian测试)。
我用来从Linux shell编译的命令行:
g++ -c -m64 -pipe -O2 -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -I. -I. -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++-64 -o teste.o teste.cpp
要明确:向量元素不相等,我只是将它们等于2.向量中有效元素的数量随着时间表活动的数量成功安排而不断变化 - 当某个给定的活动无法放入时剩下的插槽,算法开始回滚,删除一些最后放置的活动,以便开始另一次调度尝试。
答案 0 :(得分:0)
您的测试不是将苹果与苹果进行比较。
int vec[MAX_ELEMENTS]
将在堆栈上分配,而std::vector
和QVector
将使用堆。基于堆栈的分配要快得多。如果您可以使用基于堆栈的分配,请考虑std::array
。换句话说,尝试基准:
for(int i = 0; i < max_size; ++i)
c_array[i] = i;
VS
std_vector.resize(max_size); // <- initialization, not benchmarked
for(int i = 0; i < max_size; ++i)
std_vector[i] = i;
VS
qvector.resize(max_size); // <- initialization, not benchmarked
for(int i = 0; i < max_size; ++i)
qvector[i] = i;
表现应该非常相似。
答案 1 :(得分:0)
实际上,正如MrEricSir在评论部分指出的那样,clear()
操作是test4
中真正的罪魁祸首。
如果您查看Qt文档,则会发现以下内容:
void QVector :: clear()
从矢量中删除所有元素。
注意:在Qt 5.6之前,这也释放了向量使用的内存。 从Qt 5.7开始,容量得以保留。
您可能正在使用Qt版本&lt; 5.7强制在循环内释放内存。
答案 2 :(得分:0)
这个测试开始时几乎是无稽之谈,而不仅仅是废话,但实现得很差。特别是在测试大小调整方面,使用静态大小的原始C数组。如果不进行任何调整大小,该测试如何调整大小?即使对于使用任何调整大小的容器,您也要调整已保留的值,这不会产生任何影响,因为您的MAX_ELEMENTS
在整个测试过程中永远不会发生变化。
话虽如此,对于这种微不足道的行动QVector
很可能会成为一名COW。这是Qt对容器的隐式共享,具有Copy-On-Write,这意味着执行的每个非const方法都将检查容器数据是否正在共享,以便在这种情况下分离容器数据。该检查涉及原子,其涉及同步,这是昂贵的。
如果要执行更充分的写访问测试,例如:
int elements = 30000, times = 200000;
QElapsedTimer t;
int * ia = new int[elements];
t.start();
for (int it = 0; it < times; ++ it) {
for (int ic = 0; ic < elements; ++ic) {
ia[ic] = 2;
}
}
qDebug() << t.elapsed() << " msec for raw array";
QVector<int> iqv(elements);
t.restart();
for (int it = 0; it < times; ++ it) {
for (int ic = 0; ic < elements; ++ic) {
iqv[ic] = 2;
}
}
qDebug() << t.elapsed() << " msec for qvector";
std::vector<int> isv;
isv.reserve(elements);
t.restart();
for (int it = 0; it < times; ++ it) {
for (int ic = 0; ic < elements; ++ic) {
isv[ic] = 2;
}
}
qDebug() << t.elapsed() << " msec for std::vector";
你会看到与上述内容产生很大共鸣的结果,在我的系统上结果是:
1491 msec for raw array
4238 msec for qvector
1491 msec for std::vector
原始/ C数组和std::vector
的时间几乎相同,而QVector
则萎缩。
如果我们通过累积容器值来测试阅读情况,那么请注意,在这种情况下,我们使用at(index) const
QVector
:
2169 msec for raw array
2170 msec for qvector
2801 msec for std::vector
没有COW的惩罚QVector
具有与原始C数组相同的性能。 std::vector
在这里失败,虽然我不确定为什么,也许其他人可以详细说明。