我有一个整数数组,我正在遍历它们:
for (int i = 0; i < data.Length; i++)
{
// do a lot of stuff here using data[i]
}
如果我这样做:
for (int i = 0; i < data.Length; i++)
{
int value = data[i];
// do a lot of stuff with value instead of data[i]
}
是否有任何性能增益/损失?
根据我的理解,C/C++ 数组元素是直接访问的,即一个 n 元素的整数数组有一个长度为 n * sizeof(int) 的连续内存块,而程序通过执行类似 *data 的操作来访问元素 i [i] = *数据[0] + (i * sizeof(int))。 (请原谅我滥用符号,但你明白我的意思。)
所以这意味着 C/C++ 在引用数组变量时应该没有性能增益/损失。
C# 呢? C# 有很多额外的开销,比如 data.Length、data.IsSynchronized、data.GetLowerBound()、data.GetEnumerator()。
显然,C# 数组与 C/C++ 数组不同。
那么结论是什么?我应该存储 int value = data[i] 并使用 value,还是没有性能影响?
最佳答案
你可以吃蛋糕也可以吃。在许多情况下,抖动优化器可以轻松确定数组索引访问是安全的,不需要检查。像您在问题中遇到的任何 for 循环就是这样一种情况,抖动知道索引变量的范围。并且知道再次检查它是没有意义的。
您可以从生成的机器代码中看到这一点的唯一方法。我将给出一个带注释的示例:
static void Main(string[] args) {
int[] array = new int[] { 0, 1, 2, 3 };
for (int ix = 0; ix < array.Length; ++ix) {
int value = array[ix];
Console.WriteLine(value);
}
}
Starting at the for loop, ebx has the pointer to the array:
for (int ix = 0; ix < array.Length; ++ix) {
00000037 xor esi,esi ; ix = 0
00000039 cmp dword ptr [ebx+4],0 ; array.Length < 0 ?
0000003d jle 0000005A ; skip everything
int value = array[ix];
0000003f mov edi,dword ptr [ebx+esi*4+8] ; NO BOUNDS CHECK !!!
Console.WriteLine(value);
00000043 call 6DD5BE38 ; Console.Out
00000048 mov ecx,eax ; arg = Out
0000004a mov edx,edi ; arg = value
0000004c mov eax,dword ptr [ecx] ; call WriteLine()
0000004e call dword ptr [eax+000000BCh]
for (int ix = 0; ix < array.Length; ++ix) {
00000054 inc esi ; ++ix
00000055 cmp dword ptr [ebx+4],esi ; array.Length > ix ?
00000058 jg 0000003F ; loop
数组索引发生在地址 00003f,ebx 有数组指针,esi 是索引,8 是数组元素在对象中的偏移量。请注意如何不根据数组边界再次检查 esi 值。它的运行速度与 C 编译器生成的代码一样快。
关于c# - 在 C# 中,引用数组变量是否更慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5575155/