【问题标题】:Why is sorting a std::vector of std::tuple's faster than sorting a vector of std::arrays?为什么对 std::tuple 的 std::vector 进行排序比对 std::arrays 的向量进行排序更快?
【发布时间】:2021-01-21 17:04:49
【问题描述】:

我很想知道排序 vector <vector<int>> 是否会比排序 vector <array <int, 3>> 慢。 vector 的尺寸是 1000000 x 3,下面是我的驱动代码实现这个:

#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
#include <vector>

using namespace std;

int main()
{
    vector <vector<int>> v(1000000, vector <int> (3));

    srand(time(nullptr));
    for(int i = 0; i < 1000000; ++i){
        for(int j = 0; j < 3; ++j){
            v[i][j] = rand();
        }
    }

    double start = clock();
    sort(v.begin(), v.end());
    cout << (clock()-start)/(CLOCKS_PER_SEC/1000) << endl;

    return 0;
}

使用 gcc 7.5.0 编译 g++ -O3 sorting_test.cxx,我得到了大约 300 毫秒的运行时间。将 v 声明为 vector &lt;array &lt;int, 3&gt;&gt; 将运行时间减半至大约 149 毫秒。

但是,将v 声明为vector &lt;tuple&lt;int, int, int&gt;&gt; 击败了上述两个选项,平均运行时间约为100 ms

我可以理解为什么array 选项比vector 选项更快(array 大小是一个常量表达式,与vector 不同),但我不知道为什么tuple 会胜出他们都。有人可以向我解释一下吗?

填写tuple &lt;int, int, int&gt;s的代码是

srand(time(nullptr));
for(int i = 0; i < 1000000; ++i){
    get <0> (v[i]) = rand();
    get <1> (v[i]) = rand();
    get <2> (v[i]) = rand();
}

【问题讨论】:

  • 我猜这与operator &lt; 是如何为vectorarraytuple 定义的有关。对于vectorarray,您需要一个循环。 tuple 可能使用折叠操作,虽然它具有相同数量的比较,但没有循环开销。
  • 显示填充元组向量的代码。此外,使用 srand(0) 获得可重复的结果可能会更好。
  • 查看 this 了解什么是折叠表达式。
  • 另外,一个向量指向一个动态分配的内存,这对于缓存利用率来说更糟糕。数组向量连续存储所有数据。此外,交换两个向量涉及 48 个字节(在 64 位拱上),而在这种情况下交换数组只有一半。
  • 内部交换被执行。在tuple 的情况下,要交换的内存量可能会更低

标签: c++ arrays sorting vector tuples


【解决方案1】:

虽然整个程序的反汇编量太大,但这证明了operator&lt;arraytuple之间的核心区别:https://godbolt.org/z/h1Y33e

基本上,在元组版本中,您有 3 个元素的固定比较,而在数组版本中,您有一个循环。

虽然我很惊讶编译器没有展开循环。

编辑:看起来clang确实优化了它们,非循环代码:https://godbolt.org/z/cMExTb(我没有完全阅读它,但我只看到向前跳转)

【讨论】:

  • 比较交换操作的汇编可能也很有趣:godbolt.org/z/sGsK7Y.
  • 在这种特定情况下(小数组),数组应该等于 perf 中的元组,但如果数组更大,则可能会丢失。
  • 对于clang asm,数组和元组版本的指令完全相同,但是由于libstdc++的std::tuple的布局是向后的,所以它们读取三个int的顺序不同。
猜你喜欢
  • 1970-01-01
  • 2010-09-19
  • 1970-01-01
  • 2011-06-04
  • 1970-01-01
  • 2021-10-28
  • 1970-01-01
  • 1970-01-01
  • 2016-10-22
相关资源
最近更新 更多