为什么在Array.AsSpan()上循环更快


|         Method |     Mean |    Error |   StdDev |
|--------------- |---------:|---------:|---------:|
|  ArrayRefIndex | 661.9 us | 12.95 us | 15.42 us |
| ArraySpanIndex | 640.4 us |  4.08 us |  3.82 us |

为什么在array.AsSpan()上循环比直接在源阵列上循环快?

public struct Struct16
{
public int A;
public int B;
public int C;
public int D;
}
public class Program
{
public const int COUNT = 100000;

static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<Program>();
}
[Benchmark]
public int ArrayRefIndex()
{
Struct16[] myArray = new Struct16[COUNT];
int sum = 0;
for (int i = 0; i < myArray.Length; i++)
{
ref Struct16 value = ref myArray[i];
sum += value.A = value.A + value.B + value.C + value.D;
}
return sum;
}
[Benchmark]
public int ArraySpanIndex()
{
Struct16[] myArray = new Struct16[COUNT];
int sum = 0;
Span<Struct16> span = myArray.AsSpan();
for (int i = 0; i < span.Length; i++)
{
ref Struct16 value = ref span[i];
sum += value.A = value.A + value.B + value.C + value.D;
}
return sum;
}
}

简短回答

Span保证";任意存储器的连续区域";这允许编译器对CLI指令进行优化。

长答案

如果您在反汇编(Debug->Windows->反汇编(中打开提供的代码,您将在ArrayRefIndex((中找到以下内容

ref Struct16 value = ref myArray[i];
00007FFC3E860DCC  movsxd      r8,ecx  
00007FFC3E860DCF  shl         r8,4  
00007FFC3E860DD3  lea         r8,[rax+r8+10h] // <----

";lea";代表加载有效地址。也就是说,ArrayRefIndex函数的速度要慢,因为它将结构数组视为无序内存

当我们查看ArraySpanIndex时,我们可以看到它不具有";lea";指令,而代之以仅用一个";添加"我没有确认,但这可能只是添加下一个内存位置的结构长度。无论哪种方式;lea";指令是两个函数之间唯一的增量,将罪魁祸首缩小到时间差。

ref Struct16 value = ref span[i];
00007FFC3E8613FA  movsxd      r8,ecx  
00007FFC3E8613FD  shl         r8,4  
00007FFC3E861401  add         r8,rax  // <----

相关内容

  • 没有找到相关文章

最新更新