有人可以帮助我理解为什么使用线性递增索引访问数组的速度比使用随机索引快3-4倍吗?
有什么方法可以使随机索引访问时间更快?
请考虑以下测试代码,线性返回3秒,随机返回9-10秒。
public static void test()
{
var arr = new byte[64 * 1024 * 1024];
byte b = 0;
var sw = new Stopwatch();
double timeSum = 0;
for (var i = 0; i < arr.Length; i++)
{
sw.Restart();
b = arr[i];
sw.Stop();
timeSum += sw.Elapsed.TotalMilliseconds;
}
Console.WriteLine("Linear access : " + timeSum + " ms");
timeSum = 0;
var rng = new Random();
var rnum = 0;
for (var i = 0; i < arr.Length; i++)
{
rnum = rng.Next(0, arr.Length - 1);
sw.Restart();
b = arr[rnum];
sw.Stop();
timeSum += sw.Elapsed.TotalMilliseconds;
}
sw.Stop();
Console.WriteLine("Random access : " + timeSum + " ms");
}
答案 0 :(得分:3)
在基准测试中看到的差异(4到5倍)不能仅通过高速缓存行和对数组的顺序访问来解释。的确,顺序可预测访问将更快,但是,除非您正在管理大型阵列,否则性能提升甚至接近那些数字,我会感到惊讶。
编辑 坦率地说,基准测试中的数组大小(64x 1024x1024)之间的差异令人震惊,远超出我的预期。所以我的第一印象是完全错误!
问题是您的基准。您正在测量;您无法用System.Diagnostics.Stopwatch
的信心来衡量个人查找。
试图提出一个公平的基准是非常棘手的,因为没有简单的方法可以将随机性生成与查找隔离开来。我并没有考虑太多,但是下面至少尝试将苹果与苹果进行比较:诀窍是预先生成随机数组和顺序数组,然后进行基准双重查找:
static void Main(string[] args)
{
lookUpArray(1, new[] { 0 }, new[] {0}); //warmup JITTER
var r = new Random();
const int arraySize = 10000;
const int repetitions = 10000;
var lookupArray = new int[arraySize]; //values dont matter
var sequentialArray = Enumerable.Range(0, arraySize).ToArray();
var randomArray = sequentialArray.Select(i => r.Next(0, arraySize)).ToArray();
for (var i = 0; i < 10; i++)
{
var sw = Stopwatch.StartNew();
lookUpArray(repetitions, lookupArray, randomArray);
sw.Stop();
Console.WriteLine($"Random: {sw.ElapsedMilliseconds} ms");
sw.Reset();
sw.Start();
lookUpArray(repetitions, lookupArray, sequentialArray);
sw.Stop();
Console.WriteLine($"Sequential: {sw.ElapsedMilliseconds} ms");
}
}
private static void lookUpArray(int repetitions, int[] lookupArray, int[] indexArray)
{
for (var r = 0; r < repetitions; r++)
{
for (var i = 0; i < indexArray.Length; i++)
{
var _ = lookupArray[indexArray[i]];
}
}
}
无论如何我都不是基准测试专家,所以这可能在很多方面都很糟糕,但是我认为这是一个比较公平的比较。