在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:丹·布莱恩特下面的回答是为什么我没有写一个基准来开始,太容易出错。
答案 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大师,所以我不知道哪个排序在执行时间方面更有效率。但是,任何差异可能都是微不足道的,因为主要的潜在开销(构造函数方法调用)是内联的。