簡體   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