c# - 在 C# 中,引用数组变量是否更慢?

标签 c# .net arrays performance optimization

我有一个整数数组,我正在遍历它们:

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/

相关文章:

c# - 这是如何导致无限循环的?

c# - 检查两个字符串数组中是否有相同的元素?

c# - Entity Framework 仅保存我的一些字段

c# - MessageBox 按钮 - 设置语言?

.net - 使用反射获取父类的名称

c# - UI自动化和菜单项

python - Numpy 3d 数组按最外层索引转换为 2d 数组

javascript - Jquery 数组。如何一次显示与if语句匹配的数组元素?

c# - Google Maps API - 从 JSON 响应中读取地点详细信息

javascript - JS 将包含对象值的数组分配给对象键