QVector <int>写入/调整大小的性能

时间:2017-01-05 19:35:38

标签: c++ qt

我试图将一些使用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.向量中有效元素的数量随着时间表活动的数量成功安排而不断变化 - 当某个给定的活动无法放入时剩下的插槽,算法开始回滚,删除一些最后放置的活动,以便开始另一次调度尝试。

3 个答案:

答案 0 :(得分:0)

您的测试不是将苹果与苹果进行比较。

  • int vec[MAX_ELEMENTS]将在堆栈上分配,而std::vectorQVector将使用堆。基于堆栈的分配要快得多。如果您可以使用基于堆栈的分配,请考虑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在这里失败,虽然我不确定为什么,也许其他人可以详细说明。