【问题标题】:Why does switching the order of for loops significantly change the execution time?为什么切换 for 循环的顺序会显着改变执行时间?
【发布时间】:2020-06-10 12:35:20
【问题描述】:

在下面的代码中,我有 2 个嵌套的 for 循环。第二个交换了 for 循环的顺序,运行速度明显更快。

这纯粹是缓存局部性问题(第一个代码在向量上循环多次,而第二个代码在向量上循环一次),还是有其他我不理解的问题?

int main() 
{ 
  using namespace std::chrono;
  auto n = 1 << 12;
  vector<int> v(n);

  high_resolution_clock::time_point t1 = high_resolution_clock::now();
  for(int i = 0; i < (1 << 16); ++i)
  {
    for(const auto val : v) i & val;
  }
  high_resolution_clock::time_point t2 = high_resolution_clock::now();
  duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
  std::cout << "It took me " << time_span.count() << " seconds.";
  std::cout << std::endl;

  t1 = high_resolution_clock::now();
  for(const auto val : v)
  {
     for(int i = 0; i < (1 << 16); ++i) i & val;
  }
  t2 = high_resolution_clock::now();
  time_span = duration_cast<duration<double>>(t2 - t1);
  std::cout << "It took me " << time_span.count() << " seconds.";
  std::cout << std::endl;
}

【问题讨论】:

  • 您是否在反汇编程序中验证了编译器并没有简单地优化掉一些循环?
  • @cdhowie。不,我不知道该怎么做,因为我以前从未看过汇编代码。你有参考吗?
  • See here -- gcc 和 clang 都优化了 -O3 的两个循环。它实际上没有测量任何东西。
  • 现在的编译器已经相当不错了。在进行基准测试时,您必须将结果用于某事,并使其足够困难,以使编译器不会缩短您的计算并简单地预先计算结果。
  • @lamanon 不,没有

标签: c++ vector


【解决方案1】:

正如所写,第二个循环只需要从向量 v 中读取每个 val 一次。第一个版本需要在每个 i 的内部循环中从向量 v 中读取每个 val 一次,因此总共需要 65536 次。

因此,如果不进行任何优化,这将使第二个循环快几倍。当优化开启得足够高时,编译器会发现所有这些计算都没有取得任何成果,而且是不必要的,并将它们全部丢弃。然后,您的执行时间将降至零。

如果您更改代码以对结果执行某些操作(例如将所有值 i 和 val 相加,然后打印总数),一个非常好的编译器可能会发现两段代码产生相同的结果并使用更快的两种情况的方法。

【讨论】:

  • 由于缓存局部性,从向量中读取值是否会增加执行时间?我的印象是,因为它是具有连续元素的单个向量,所以缓存位置不是问题。
猜你喜欢
  • 1970-01-01
  • 2016-01-10
  • 1970-01-01
  • 2014-12-22
  • 2018-03-24
  • 2013-03-21
  • 2021-03-24
  • 2017-09-21
  • 1970-01-01
相关资源
最近更新 更多