簡體   English   中英

返回內部if塊或寫入if / else塊之間在性能上有區別嗎?

[英]Is there a performance difference between returning inside if block, or writing if/else block?

我正在查看我的項目以重構一些代碼,並意識到我已經寫了如下代碼:

if(errorCode > 0)
{
   DisplayError(errorCode);
   return;
}

// Continue to do stuff otherwise.

您可能已經猜到了,該函數的返回類型為void。 當我開始研究時,我在思考將其放入if / else塊之間是否有真正的區別:

if(errorCode > 0)
{
   DisplayError(errorCode);
}
else
{
   // Do other stuff
}

else塊將一直持續到函數結束,因此控制流程本質上是相同的。 這里是否存在性能差異,或者應該使用約定,還是這兩個確實完全相同?

兩種情況下生成的代碼完全相同。

(在第一個示例中,您沒有在代碼中加上括號,但是我只是假設這是一個錯字,實際上您是在使用returnelse來詢問之間的區別。)

如果您查看為這兩種方法生成的代碼:

public static void Test1(int errorCode) {
  if (errorCode > 0) {
    Console.WriteLine(errorCode);
    return;
  }
  Console.WriteLine("ok");
}

public static void Test2(int errorCode) {
  if (errorCode > 0) {
    Console.WriteLine(errorCode);
  } else {
    Console.WriteLine("ok");
  }
}

它看起來像這樣:

            if (errorCode > 0) {
011A00DA  in          al,dx  
011A00DB  push        eax  
011A00DC  mov         dword ptr [ebp-4],ecx  
011A00DF  cmp         dword ptr ds:[10F3178h],0  
011A00E6  je          011A00ED  
011A00E8  call        7470C310  
011A00ED  cmp         dword ptr [ebp-4],0  
011A00F1  jle         011A0100  
                Console.WriteLine(errorCode);
011A00F3  mov         ecx,dword ptr [ebp-4]  
011A00F6  call        73C5A920  
                return;
011A00FB  nop  
011A00FC  mov         esp,ebp  
011A00FE  pop         ebp  
011A00FF  ret  
            }
            Console.WriteLine("ok");
011A0100  mov         ecx,dword ptr ds:[3E92190h]  
011A0106  call        7359023C  
        }
011A010B  nop  
011A010C  mov         esp,ebp  
011A010E  pop         ebp  
011A010F  ret

和:

            if (errorCode > 0) {
011A0122  in          al,dx  
011A0123  push        eax  
011A0124  mov         dword ptr [ebp-4],ecx  
011A0127  cmp         dword ptr ds:[10F3178h],0  
011A012E  je          011A0135  
011A0130  call        7470C310  
011A0135  cmp         dword ptr [ebp-4],0  
011A0139  jle         011A0148  
                Console.WriteLine(errorCode);
011A013B  mov         ecx,dword ptr [ebp-4]  
011A013E  call        73C5A920  
011A0143  nop  
011A0144  mov         esp,ebp  
011A0146  pop         ebp  
011A0147  ret  
            } else {
                Console.WriteLine("ok");
011A0148  mov         ecx,dword ptr ds:[3E92190h]  
011A014E  call        7359023C  
            }
        }
011A0153  nop  
011A0154  mov         esp,ebp  
011A0156  pop         ebp  
011A0157  ret

直到最后一條指令為止,生成的代碼完全相同。

無關緊要的是,您也可以使用出色的LinqPad進行IL拆卸,但是要評論太大。

有趣的是,在調試模式下僅分解到IL為止,Guffa的Test2 IL中有幾個額外的nop ,它們按照Guffa的答案在x86 / x64 JIT中進行編譯:

調試IL:

Test1:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldc.i4.0    
IL_0003:  cgt         
IL_0005:  ldc.i4.0    
IL_0006:  ceq         
IL_0008:  stloc.0     // CS$4$0000
IL_0009:  ldloc.0     // CS$4$0000
IL_000A:  brtrue.s    IL_0016
IL_000C:  nop         
IL_000D:  ldarg.0     
IL_000E:  call        System.Console.WriteLine
IL_0013:  nop         
IL_0014:  br.s        IL_0021
IL_0016:  ldstr       "ok"
IL_001B:  call        System.Console.WriteLine
IL_0020:  nop         
IL_0021:  ret         

Test2:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldc.i4.0    
IL_0003:  cgt         
IL_0005:  ldc.i4.0    
IL_0006:  ceq         
IL_0008:  stloc.0     // CS$4$0000
IL_0009:  ldloc.0     // CS$4$0000
IL_000A:  brtrue.s    IL_0017
IL_000C:  nop         
IL_000D:  ldarg.0     
IL_000E:  call        System.Console.WriteLine
IL_0013:  nop         
IL_0014:  nop     <-- Extra    
IL_0015:  br.s        IL_0024
IL_0017:  nop     <-- Extra
IL_0018:  ldstr       "ok"
IL_001D:  call        System.Console.WriteLine
IL_0022:  nop         
IL_0023:  nop     <-- Extra    
IL_0024:  ret         

IMO非常有趣,因為從處理器來看,如果處理器nop's實際上被執行,則是浪費的,但是如果填充它們以允許跳轉到達后續對齊邊界,則這是有益的。 這就引出了一個問題,即為什么IL完全對nops持保留意見,因為填充優化應該只涉及JIT編譯器。 答案似乎無關,大括號,可能是出於調試原因

對於發布模式,Guffa是正確的-在發布模式下編譯IL會丟棄IL中的所有nop-IL nops完全存在於其中以允許調試中斷/對括號進行逐步調試。 抖動重新引入了x86點,以實現均勻指令對齊,並且兩種方法是相同的。

發行版IL(Test1和Test2):

IL_0000:  ldarg.0     
IL_0001:  ldc.i4.0    
IL_0002:  ble.s       IL_000B
IL_0004:  ldarg.0     
IL_0005:  call        System.Console.WriteLine
IL_000A:  ret         
IL_000B:  ldstr       "ok"
IL_0010:  call        System.Console.WriteLine
IL_0015:  ret  

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM