对于具有更多字段的类型,通过数组进行字段访问更慢

dtb*_*dtb 9 c# arrays performance .net-4.5

以下简短但完整的示例程序

const long iterations = 1000000000;

T[] array = new T[1 << 20];
for (int i = 0; i < array.Length; i++)
{
    array[i] = new T();
}

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
    array[i % array.Length].Value0 = i;
}

Console.WriteLine("{0,-15}  {1}   {2:n0} iterations/s",
    typeof(T).Name, sw.Elapsed, iterations * 1000d / sw.ElapsedMilliseconds);
Run Code Online (Sandbox Code Playgroud)

T替换如下类型的

class SimpleClass                   struct SimpleStruct
{                                   {
    public int Value0;                  public int Value0;
}                                   }

class ComplexClass                  struct ComplexStruct
{                                   {
    public int Value0;                  public int Value0;
    public int Value1;                  public int Value1;
    public int Value2;                  public int Value2;
    public int Value3;                  public int Value3;
    public int Value4;                  public int Value4;
    public int Value5;                  public int Value5;
    public int Value6;                  public int Value6;
    public int Value7;                  public int Value7;
    public int Value8;                  public int Value8;
    public int Value9;                  public int Value9;
    public int Value10;                 public int Value10;
    public int Value11;                 public int Value11;
}                                   }
Run Code Online (Sandbox Code Playgroud)

在我的机器上产生以下有趣的结果(Windows 7 .NET 4.5 32位)

SimpleClass      00:00:10.4471717   95,721,260 iterations/s
ComplexClass     00:00:37.8199150   26,441,736 iterations/s
SimpleStruct     00:00:12.3075100   81,254,571 iterations/s
ComplexStruct    00:00:32.6140182   30,661,679 iterations/s

问题1:为什么ComplexClass这么慢SimpleClass?经过的时间似乎随着班级中的字段数量线性增加.写入具有大量字段的类的第一个字段与写入只有一个字段的类的第一个字段不应该有很大不同,不是吗?

问题2:为什么ComplexStructSimpleStruct?看看IL代码显示i直接写入数组,而不是本地实例ComplexStruct,然后将其复制到数组中.因此,复制更多字段不会产生任何开销.

奖金问题:为什么ComplexStruct比快ComplexClass


编辑:使用较小的数组更新测试结果T[] array = new T[1 << 8];:

SimpleClass      00:00:13.5091446   74,024,724 iterations/s
ComplexClass     00:00:13.2505217   75,471,698 iterations/s
SimpleStruct     00:00:14.8397693   67,389,986 iterations/s
ComplexStruct    00:00:13.4821834   74,172,971 iterations/s

因此,几乎没有任何区别SimpleClassComplexClass,只有一小之间的差异SimpleStructComplexStruct.但是,性能显著的下降SimpleClassSimpleStruct.


编辑:现在T[] array = new T[1 << 16];:

SimpleClass      00:00:09.7477715  102,595,670 iterations/s
ComplexClass     00:00:10.1279081  98,745,927 iterations/s
SimpleStruct     00:00:12.1539631  82,284,210 iterations/s
ComplexStruct    00:00:10.5914174  94,419,790 iterations/s

结果1<<15就像是1<<8,结果1<<17就像1<<20.

Car*_*000 7

问题1的可能答案:

您的CPU一次将内存读入其缓存中.

使用较大的数据类型,您可以在每个缓存页面上放置更少的对象.即使您只编写一个32位值,仍然需要CPU缓存中的页面.使用较小的对象,您可以在下次需要从主内存中读取之前完成更多循环.