C#结构分配效率

时间:2014-04-24 20:08:46

标签: c# struct

在C#中,我有一个结构数组,我需要为每个结构赋值。最有效的方法是什么?我可以分配每个字段,为每个字段索引数组:

array[i].x = 1;
array[i].y = 1;

我可以在堆栈上构造一个新结构并将其复制到数组中:

array[i] = new Vector2(1, 2);

还有其他方法吗?我可以调用一个方法并通过ref传递结构,但我猜测方法调用开销是不值得的。

如果结构大小很重要,那么所讨论的结构有2-4个float或byte类型的字段。

在某些情况下,我需要为多个数组条目分配相同的值,例如:

Vector2 value = new Vector2(1, 2);
array[i] = value;
array[i + 1] = value;
array[i + 2] = value;
array[i + 3] = value;

这会改变哪种方法更有效吗?

我知道这个级别很低,但我做了数百万次并且我很好奇。

编辑:我打了一个基准:

this.array = new Vector2[100];
Vector2[] array = this.array;
for (int i = 0; i < 1000; i++){
    long startTime, endTime;
    startTime = DateTime.Now.Ticks;
    for (int x = 0; x < 100000000; x++) {
        array[0] = new Vector2(1,2);
        array[1] = new Vector2(3,4);
        array[2] = new Vector2(5,6);
        array[3] = new Vector2(7,8);
        array[4] = new Vector2(9,0);
        array[5] = new Vector2(1,2);
        array[6] = new Vector2(3,4);
        array[7] = new Vector2(5,6);
        array[8] = new Vector2(7,8);
        array[9] = new Vector2(9,0);
    }
    endTime = DateTime.Now.Ticks;
    double ns = ((double)(endTime - startTime)) / ((double)loopCount);
    Debug.Log(ns.ToString("F"));
}

这报告了〜0.77ns,另一个索引并分配了结构域的版本给出了~0.24ns,FWIW。与结构堆栈分配和复制相比,数组索引看起来很便宜。在移动设备上看到性能可能会很有趣。

编辑2:丹·布莱恩特下面的回答是为什么我没有写一个基准来开始,太容易出错。

1 个答案:

答案 0 :(得分:3)

我很好奇第一种情况(字段赋值与构造函数调用),所以我做了一个发布版本并附加了后JIT以查看反汇编。 (x64)代码如下所示:

            var array = new Vector2[10];
00000000  mov         ecx,191372h 
00000005  mov         edx,0Ah 
0000000a  call        FFF421C4 
0000000f  mov         edx,eax 

            array[i].x = 1;
00000011  cmp         dword ptr [edx+4],0 
00000015  jbe         0000003E 
00000017  lea         eax,[edx+8] 
0000001a  fld1 
0000001c  fstp        qword ptr [eax] 
            array[i].y = 1;
0000001e  fld1 
00000020  fstp        qword ptr [edx+10h] 

            array[i] = new Vector2(1, 1);
00000023  add         edx,8 
00000026  mov         eax,edx 
00000028  fld1 
0000002a  fld1 
0000002c  fxch        st(1) 
0000002e  fstp        qword ptr [eax] 
00000030  fstp        qword ptr [eax+8] 

有一点值得注意的是,&#39;构造函数调用&#39;在调试器外部使用发布版本时内联,因此,原则上,设置字段或调用构造函数之间应该没有区别。也就是说,抖动在这里做了一些有趣的事情。

对于&#39;构造函数&#39;版本,它使用两个浮点堆栈槽并将它们同时存储到结构存储器(fld1,fld1,fstp,fstp。)它还有一个fxch(交换),这有点傻,因为两个槽都包含常量值1,但不是大多数应用程序的高优先级优化目标,我假设。

对于&#39;个别字段&#39;版本,它只使用FPU堆栈上的一个插槽,通过拆分写入(fld1,fstp,fld1,fstp)。我不是x64大师,所以我不知道哪个排序在执行时间方面更有效率。但是,任何差异可能都是微不足道的,因为主要的潜在开销(构造函数方法调用)是内联的。