为什么这个 C++ 代码不快?

Why this c++ code is not faster?

所有: 我有两段代码。第一个是:

#include <iostream>

using namespace std;

static constexpr long long n = 1000000000;

int main() {
  int sum = 0;
  int* a = new int[n];
  int* b = new int[n];

  for (long long i=0; i<n; i++) {
    a[i] = static_cast<int>(i);
  }

  for (long long i=0; i<n; i++) {
    sum *= a[i];
    sum += a[i];
  }

  for (long long i=0; i<n; i++) {
    b[i] = static_cast<int>(i);
  }

  for (long long i=0; i<n; i++) {
    sum *= b[i];
    sum += b[i];
  }

  cout<<sum<<endl;
}

第二个是:

#include <iostream>

using namespace std;

constexpr long long n = 1000000000;

int main() {
  int* a = new int[n];
  int* b = new int[n];
  int sum = 0;

  for (long long i=0; i<n; i++) {
    a[i] = static_cast<int>(i);
    b[i] = static_cast<int>(i);
  }

  for (long long i=0; i<n; i++) {
    sum *= a[i];
    sum += a[i];
    sum *= b[i];
    sum += b[i];
  }

  cout<<sum<<endl;
}

我认为第一个程序应该比第二个程序快得多,因为它对缓存更友好。然而,事实是第二个更快。在我的服务器上,第一个需要 23 秒,第二个需要 20 秒,有人可以解释一下吗?

对于第一段代码,您使用 4个循环完成任务。

for (long long i=0; i<n; i++) {
    a[i] = static_cast<int>(i);
  }

  for (long long i=0; i<n; i++) {
    sum *= a[i];
    sum += a[i];
  }

  for (long long i=0; i<n; i++) {
    b[i] = static_cast<int>(i);
  }

  for (long long i=0; i<n; i++) {
    sum *= b[i];
    sum += b[i];
  }

而在第二个中你只使用了 2 个循环来完成任务。

for (long long i=0; i<n; i++) {
    a[i] = static_cast<int>(i);
    b[i] = static_cast<int>(i);
  }

  for (long long i=0; i<n; i++) {
    sum *= a[i];
    sum += a[i];
    sum *= b[i];
    sum += b[i];
  }

在您提供的第二段代码中发生的迭代次数要少得多。

您没有看到缓存友好性优势,因为访问模式仍然太简单,即使在您预测速度较慢的版本中也是如此。

两个(或更多)并发的直线输入流是现代 CPU 可以检测到并在需要之前流入 L1 的东西。

它还可以让多个 SDRAM 组同时投入有用的工作。如果您使用的是 Linux,您将无法对其进行太多控制,因为页面是随机映射的(我认为;这仍然是真的吗?),但您可以尝试使用 mmap()MAP_HUGETLB 参数,然后从分配开始尝试不同的偏移量。

如果您想了解以缓存友好顺序安排计算的优势,您或许应该在二维数组中尝试不同的访问模式。

缓存在您的示例中没有发挥重要作用。对数组的线性访问比缓存大,并且访问之间几乎没有计算,将始终受到内存带宽的限制,而不是缓存。他们根本没有足够的时间通过预取来填充。

您正在测试的是编译器将您的 four/two 循环优化为一个循环的聪明程度,或者他的聪明程度以了解您在做什么并简单地打印结果。