【问题标题】:Why might std::vector be faster than a raw dynamically allocated array?为什么 std::vector 可能比原始动态分配的数组更快?
【发布时间】:2011-07-25 22:56:11
【问题描述】:

与一位同事讨论的结果是,我最终编写了基准测试来测试 std::vector 与原始动态分配的数组,结果令人惊讶。

我的测试如下:

#include "testconsts.h" // defines NUM_INTS across all tests
#include <vector>

int main()
{
    const int numInts = NUM_INTS;
    std::vector<int>                     intVector( numInts );
    int * const                          intArray       = new int[ numInts ];

    ++intVector[0]; // force access to affect optimization
    ++intArray[0];  // force access to affect optimization

    for( int i = 0; i < numInts; ++i )
    {
        ++intArray[i];
    }

    delete[] intArray;
    return 0;
}

和:

#include "testconsts.h" // defines NUM_INTS across all tests
#include <vector>

int main()
{
    const int numInts = NUM_INTS;
    std::vector<int>                     intVector( numInts );
    int *                                intArray       = new int[ numInts ];

    ++intArray[0];  // force access to affect optimization
    ++intVector[0]; // force access to affect optimization

    for( int i = 0; i < numInts; ++i )
    {
        ++intVector[i];
    }

    delete[] intArray;
    return 0;
}

它们是用 g++ -O3 和 gcc 4.4.3 编译的

使用time 多次运行基准测试的结果类似于:

数组:

real    0m0.757s
user    0m0.176s
sys     0m0.588s

矢量:

real    0m0.572s
user    0m0.268s
sys     0m0.304s

三件事很清楚:

  1. 数组在用户时间上更快
  2. 向量速度更快,系统时间更短
  3. 在这场战斗中,vector 赢得了所有胜利

问题是“为什么?”。

我猜测系统时间问题一定与页面错误有关,但我无法准确描述为什么会有更多页面错误。

至于用户时间问题,我不太感兴趣,但我仍然很好奇对此的看法。我以为它与初始化有关,尽管我没有将初始化值传递给向量构造函数,所以我不知道。

【问题讨论】:

  • 尝试使用其他类型的向量...这可能与针对 32 位整数的向量类的优化有关。他们这样做是为了布尔。
  • @Thomas:这太错误了。向量在内部使用分配的空间用作数组。 vector 是一个完全不同的动物,一个设计错误
  • 比较组装怎么样?这应该会给你一个很好的主意。
  • @Catskul:你已经知道答案了:更多的页面错误,你只需要解释为什么会这样,你不需要去汇编,高级 C++ 的解释就足够了: std::vector 默认会在构造时初始化元素,而您的代码中的 new 不会。数组测试支付两个容器的成本,而向量测试只有自己的成本。

标签: c++ performance stl vector profiling


【解决方案1】:

区别不在于向量与动态数组相比的性能,而在于您执行的内存访问次数。

实际上,在向量测试中,您正在重新访问缓存内存,而在数组版本中您没有。无论哪种情况,您都需要为缓存矢量版本付出代价。

在向量测试中,您为数组分配了动态内存,但保持不变,因为内存从未被触及,因此该操作不会出现页面错误。向量被创建、初始化,然后第二遍将访问已经缓存的数据(如果大小适合缓存,如果不适合,则不会在缓存中,但两个版本都会产生相同的成本)。

另一方面,在测试数组时,向量构造函数初始化元素,这意味着如果您尝试分析数组的行为,则遍历向量内容数组元素被遍历。应用程序使用的内存访问、页面错误和内存的数量翻倍。

您可以尝试修改代码,以便像这样执行动态分配:

int * intArray = new int[ numInts ](); // note extra ()

这将值初始化整个数组,或者你如何初始化数组内容。运行修改后的测试版本的结果应该是相似的。

【讨论】:

  • 我读了几遍才明白,但重新进行基准测试表明您是正确的。我希望您不介意我编辑您的答案以帮助澄清。
  • @Catskul:我不介意,我深夜写的,问题已经够复杂了。关键是:在向量基准测试中,您只触及向量内容,在数组基准测试中,您触及数组和向量内容,因此访问的内存量是所有问题的两倍..跨度>
【解决方案2】:

您是否多次运行测试?基准测试是一个艰难的过程,必须依靠平均值才能获得任何有意义的结果;在您运行阵列基准测试时,可能有几个 CPU 周期专门用于其他事情,从而减慢了速度。我希望给定足够多的结果,它们会是相似的,因为 std::vector 是用 C 风格的数组编写的。

【讨论】:

  • 或许这应该是一条评论
  • @Nicklammort:啊,好吧,抱歉,我不确定是要发表评论还是回答。
  • 对我来说似乎是一个有效的答案,尽管它可能更坚定一些。是的,它们应该具有相同的性能。
  • 它们已经运行了 10 次,结果相同。好主意。我会更新以提及这一点。
猜你喜欢
  • 2014-10-24
  • 1970-01-01
  • 1970-01-01
  • 2014-04-18
  • 2016-06-08
  • 2013-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多