为什么 std::vector 比数组慢?

Why is std::vector slower than an array?

当我运行以下程序(启用优化)时,for循环与std::vector大约需要0.04秒,而for循环与数组需要 0.0001 秒。

#include <iostream>
#include <vector>
#include <chrono>

int main()
{
    int len = 800000;
    int* Data = new int[len];

    int arr[3] = { 255, 0, 0 };
    std::vector<int> vec = { 255, 0, 0 };

    auto start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < len; i++) {
        Data[i] = vec[0];
    }
    auto finish = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> elapsed = finish - start;
    std::cout << "The vector took " << elapsed.count() << "seconds\n";

    start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < len; i++) {
        Data[i] = arr[0];
    }
    finish = std::chrono::high_resolution_clock::now();
    elapsed = finish - start;
    std::cout << "The array took " << elapsed.count() << "seconds \n";

    char s;
    std::cin >> s;
    delete[] Data;
}

该代码是我在编写 raycaster 时遇到的性能问题的简化版本。 len变量对应原程序中循环需要运行(400像素*400像素*50最大渲染距离)多少次。由于复杂的原因(也许我不完全理解如何使用数组),我必须在实际的 raycaster 中使用向量而不是数组。然而,正如这个程序所展示的那样,这只会给我每秒 20 帧,而不是令人羡慕的每秒 10,000 帧,据称使用数组可以给我(显然,这只是一个简化的性能测试)。但不管这些数字有多准确,我仍然想尽可能地提高帧率。那么,为什么向量的执行速度比数组慢很多呢?有没有办法加快速度?谢谢你的帮助。如果还有其他我做的奇怪的事情可能会影响性能,请告诉我。在研究这个问题的答案之前我什至不知道优化,所以如果还有更多类似的东西可以提高性能,请告诉我(如果你解释这些设置在属性管理器而不是命令行,因为我还不知道如何使用命令行)

这是关于缓存的。我不知道它是如何详细工作的,但是 Data[] 在使用时被 cpu 所熟知。如果将计算顺序颠倒,您可以看到 'vector is faster'。

但实际上,您既没有测试 vector 也没有测试 array。假设 vec[0] 位于 0x01 内存位置,arr[0] 位于 0xf1。唯一的区别是从不同的单个内存地址读取一个单词。因此,您正在测试我可以多快将 分配给动态分配的 array.

的元素

注意: std::chrono::high_resolution_clock 可能不足以测量滴答声。如cppreference所说,最好使用steady_clock

让我们观察一下how GCC optimizes this test program:

#include <vector>

int main()
{
    int len = 800000;
    int* Data = new int[len];

    int arr[3] = { 255, 0, 0 };
    std::vector<int> vec = { 255, 0, 0 };

    for (int i = 0; i < len; i++) {
        Data[i] = vec[0];
    }
    for (int i = 0; i < len; i++) {
        Data[i] = arr[0];
    }
    delete[] Data;
}

编译器正确地注意到向量是常量,并将其删除。为两个循环生成完全相同的代码。因此,第一个循环使用数组还是向量应该无关紧要。

.L2:
    movups  XMMWORD PTR [rcx], xmm0
    add     rcx, 16
    cmp     rsi, rcx
    jne     .L2

使您的测试程序与众不同的是循环的顺序。评论指出when a third loop is added to the beginning,两个循环耗时相同

我希望在启用优化并禁用调试的情况下,使用现代编译器访问向量的速度大约与访问数组一样快。如果您的实际程序存在明显差异,则问题出在其他地方。