繁体   English   中英

C#中具有静态类型检查的C#中的索引的Typedef,而没有运行时开销

[英]Typedef for indexes in C# with static type checking without runtime overhead

使用具有复杂索引的多维数组是很常见的情况。 当所有索引都是整数时,这真的很容易混淆,并且容易出错,因为您可以轻松地混合列和行(或您所拥有的任何东西),并且编译器无法识别问题。 实际上,应该有两种类型的索引:行和列,但是它不是在类型级别上表示的。

这是我想要的一个小例子:

var table = new int[RowsCount,ColumnsCount];
Row row = 5;
Column col = 10;
int value = table[row, col];

public void CalcSum(int[,] table, Column col)
{
    int sum = 0;
    for (Row r = 0; r < table.GetLength(0); r++)
    {
        sum += table[row, col];
    }
    return sum;
}

CalcSum(table, col); // OK
CalcSum(table, row); // Compile time error

加起来:

  • 应该对索引进行静态检查以防混淆(类型检查)
  • 重要! 它们应该是运行时高效的,因为将int封装到包含索引的自定义对象上然后将它们解开会降低性能
  • 它们应隐式转换为int以便在本机多维数组中用作索引

有什么办法可以做到这一点? 理想的解决方案是像typedef这样的东西,它仅用作编译时检查以编译为平面int。

x64抖动只会使速度减慢2倍。 它生成有趣的优化代码。 使用该结构的循环如下所示:

00000040  mov         ecx,1 
00000045  nop         word ptr [rax+rax+00000000h] 
00000050  lea         eax,[rcx-1] 
                s.Idx = j;
00000053  mov         dword ptr [rsp+30h],eax 
00000057  mov         dword ptr [rsp+30h],ecx 
0000005b  add         ecx,2 
            for (int j = 0; j < 100000000; j++) {
0000005e  cmp         ecx,5F5E101h 
00000064  jl          0000000000000050 

由于代码不常见,因此需要一些注释。 首先,偏移量为45的怪异NOP会在循环开始时对齐指令。 这使得偏移量为64的分支更快。 53处的指令看起来完全没有必要。 您在这里看到的是循环展开 ,请注意5b处的指令如何将循环计数器加2。然而,优化器不够智能,因此也看不到存储区。

最重要的是,这里没有ADD指令。 换句话说,该代码实际上并没有计算“ sum”的值。 这是因为在循环后没有在任何地方使用它,优化器可以看到该计算是无用的,并将其完全删除了。

在第二个循环中,它做得更好:

000000af  xor         eax,eax 
000000b1  add         eax,4 
            for (int j = 0; j < 100000000; j++) {
000000b4  cmp         eax,5F5E100h 
000000b9  jl          00000000000000B1 

现在,它完全删除了“求和”计算和“ i”变量分配。 它也可能删除了整个for()循环,但是抖动优化器从未做到这一点,它假设延迟是有意的。

希望到目前为止,信息已经清楚了:避免根据人工基准进行假设,并且只能描述真实的代码。 您可以通过实际显示“ sum”的值来使其更真实,这样优化器就不会丢弃计算。 在循环之后添加以下代码行:

        Console.Write("Sum = {0} ", sum);

现在,您将看到没有任何区别了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM