我预计以下程序在性能方面完全受内存限制(数组比 L3 缓存大得多)。
因此,我预计 long 数组的总和花费的时间几乎是 int 数组总和的两倍。
但它们几乎花费相同的时间:
int sum took 81 ms, result = 4999999950000000
long sum took 87 ms, result = 4999999950000000
谁能解释一下吗?
using System;
using System.Diagnostics;
using System.Linq;
namespace MemoryPerformance
{
class Program
{
static void Main(string[] args)
{
const int count = 100_000_000;
int[] intArray = Enumerable.Range(0, count).ToArray();
long[] longArray = intArray.Select(x => (long)x).ToArray();
Measure(() => intSum(intArray), " int sum");
Measure(() => longSum(longArray), "long sum");
}
static long intSum(int[] array)
{
long sum = 0;
for (int i = 0; i < array.Length; i++) sum += array[i];
return sum;
}
static long longSum(long[] array)
{
long sum = 0;
for (int i = 0; i < array.Length; i++) sum += array[i];
return sum;
}
static void Measure(Func<long> calc, string description)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
long sum = calc();
stopwatch.Stop();
Console.WriteLine($"{description} took {stopwatch.ElapsedMilliseconds} ms, result = {sum}");
}
}
}
最佳答案
您测量的时间主要是“只是CPU时间”。 如果您只对数字进行求和并省略整个内存访问,如this fork of Harolds answer ,您会发现只需将循环中的所有数字相加所需的时间几乎相同,无需从数组/内存中读取它们:
static long noSum(long[] array)
{
long sum = 0;
for (int i = 0; i < array.Length; i ++) sum += i;
return sum;
}
这意味着,即使 CPU 必须 从内存中获取数据并且无法将其全部保存在缓存中,它也可以非常高效地完成此操作,因为您没有使用随机数组访问:对于循环的情况,它有足够的时间来预取下一个缓存行,同时仍在执行计算。这导致几乎没有等待时间(推测执行任何人?!;-))。因此,对于您的情况并不重要。显然,在您需要更快地访问大量内存的情况下,就像在 Harolds“稀疏”测试用例中一样,它确实如此。
关于c# - 数组求和缺失时的预期缓存效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49116685/