为什么 std::unordered_set 比 std::set 慢?

时间:2021-02-24 11:36:25

标签: c++ performance set unordered-set

我编写了一个示例代码来比较 std::unordered_set 和 std::set 的性能。

  constexpr size_t kLoopNumber = 10000000;

  std::default_random_engine e;
  std::set<uint32_t> s1;
  std::unordered_set<uint32_t> s2;

  for (size_t i = 0; i < 10000; ++i) {
    uint32_t k = e();
    s1.emplace(k);
    s2.emplace(k);
  }

  std::vector<size_t> indices(kLoopNumber);
  std::iota(indices.begin(), indices.end(), 0);

  // std::shuffle(indices.begin(), indices.end(), e);

  size_t count = 0;
  auto pre = system_clock::now();
  // code 0
  for (size_t i = 0; i < kLoopNumber; ++i) {
    count += s1.count(indices[i]);
  }
  //
  std::cout << duration_cast<microseconds>(system_clock::now() - pre).count()
            << " us for set" << std::endl;

  pre = system_clock::now();
  // code 1
  for (size_t i = 0; i < kLoopNumber; ++i) {
    count += s2.count(indices[i]);
  }
  //
  std::cout << duration_cast<microseconds>(system_clock::now() - pre).count()
            << " us for unordered_set" << std::endl;
  // for not optimize count
  std::cout << count << std::endl;

得到如下结果:

85434 us for set
144212 us for unordered_set

如果我打乱索引。

  constexpr size_t kLoopNumber = 10000000;

  std::default_random_engine e;
  std::set<uint32_t> s1;
  std::unordered_set<uint32_t> s2;

  for (size_t i = 0; i < 10000; ++i) {
    uint32_t k = e();
    s1.emplace(k);
    s2.emplace(k);
  }

  std::vector<size_t> indices(kLoopNumber);
  std::iota(indices.begin(), indices.end(), 0);

  std::shuffle(indices.begin(), indices.end(), e);

  size_t count = 0;
  auto pre = system_clock::now();
  // code 0
  for (size_t i = 0; i < kLoopNumber; ++i) {
    count += s1.count(indices[i]);
  }
  //
  std::cout << duration_cast<microseconds>(system_clock::now() - pre).count()
            << " us for set" << std::endl;

  pre = system_clock::now();
  // code 1
  for (size_t i = 0; i < kLoopNumber; ++i) {
    count += s2.count(indices[i]);
  }
  //
  std::cout << duration_cast<microseconds>(system_clock::now() - pre).count()
            << " us for unordered_set" << std::endl;
  // for not optimize count
  std::cout << count << std::endl;

然后得到:

225042 us for set
160389 us for unordered_set

为什么洗牌后个人资料变化如此之大,有人可以解释一个重要原因吗? CPU缓存?有序设置键?还是其他原因?

提示: 编译器是 gcc 7.5.0,带有编译选项 g++ -std=c++17 -O2

PS:我更新了参考评论建议的示例代码。

0 个答案:

没有答案
相关问题