[c#] IF的表現是否優於IF-ELSE?


Answers

這裡的性能提升可以忽略不計,我稱之為微微觀微優化。 除非你計劃這樣做幾百萬次,否則請在這裡尋求可讀性。

編輯:(重新:評論中的問題)

在我看來,第一個是更具可讀性。 它以一種現成的格式明確地顯示了每種情況下字符串應該是什麼。 第二個省略了一個案例,因此審閱者必須查看代碼的其他區域以確定默認值。 為了更好地理解它,想像一下原始聲明/初始化和這個特定代碼塊之間的50行代碼。 如果在那種情況下變得不清楚那麼那將由我來決定。

Question

這些代碼塊中哪一個表現更好,哪一個更易讀? 我猜這個增益可以忽略不計,特別是在第二個區塊。 我只是好奇。

塊#1

string height;
string width;
if (myFlag == 1)
{
    height = "60%";
    width = "60%";
}
else
{
    height = "80%";
    width = "80%";
}

塊#2

string height = "80%";
string width = "80%";
if (myFlag == 1)
{
    height = "60%";
    width = "60%";
}

更新

我測試上述代碼時的結果是兩個塊執行相同的操作

塊#1

myFlag = 1:   3 Milliseconds
myFlag = 0:   3 Milliseconds

塊#2

myFlag = 1:   3 Milliseconds
myFlag = 0:   3 Milliseconds

但是我在這裡註意到的一件重要的事情(感謝Matthew Steeples在這裡回答 )是因為我測試的代碼塊沒有使用變量高度和寬度,除了if-else中的賦值和if代碼塊1的塊和編譯器分別通過完全刪除問題中的if和if-else塊來優化IL代碼,從而在此處顯示我們測試的無效結果

我已經更新了兩個代碼塊,將高度和寬度的值寫入文件,因此再次使用它們並強制編譯器運行我們的測試塊(我希望),但您可以從代碼中觀察到實際的文件寫入部分不影響我們的測試結果

這是更新的結果,C#和IL代碼

結果

塊#1

myFlag = 1:   1688 Milliseconds
myFlag = 0:   1664 Milliseconds

塊#2

myFlag = 1:   1700 Milliseconds
myFlag = 0:   1677 Milliseconds

C#.net代碼

塊#1

    public long WithIfAndElse(int myFlag)
    {
        Stopwatch myTimer = new Stopwatch();
        string someString = "";
        myTimer.Start();
        for (int i = 0; i < 1000000; i++)
        {
            string height;
            string width;
            if (myFlag == 1)
            {
                height = "60%";
                width = "60%";
            }
            else
            {
                height = "80%";
                width = "80%";
            }
            someString = "Height: " + height + Environment.NewLine + "Width: " + width;
        }
        myTimer.Stop();
        File.WriteAllText("testifelse.txt", someString);
        return myTimer.ElapsedMilliseconds;
    }

塊#2

    public long WithOnlyIf(int myFlag)
    {
         Stopwatch myTimer = new Stopwatch();
        string someString = "";
        myTimer.Start();
        for (int i = 0; i < 1000000; i++)
        {
            string height = "80%";
            string width = "80%";
            if (myFlag == 1)
            {
                height = "60%";
                width = "60%";
            }
            someString = "Height: " + height + Environment.NewLine + "Width: " + width;
        }
        myTimer.Stop();
        File.WriteAllText("testif.txt", someString);
        return myTimer.ElapsedMilliseconds;
    }

IL代碼由ildasm.exe生成

塊#1

.method public hidebysig instance int64  WithIfAndElse(int32 myFlag) cil managed
{
  // Code size       144 (0x90)
  .maxstack  3
  .locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,
           [1] string someString,
           [2] int32 i,
           [3] string height,
           [4] string width,
           [5] string[] CS$0$0000)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldstr      ""
  IL_000b:  stloc.1
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_0012:  ldc.i4.0
  IL_0013:  stloc.2
  IL_0014:  br.s       IL_0070
  IL_0016:  ldarg.1
  IL_0017:  ldc.i4.1
  IL_0018:  bne.un.s   IL_0029
  IL_001a:  ldstr      "60%"
  IL_001f:  stloc.3
  IL_0020:  ldstr      "60%"
  IL_0025:  stloc.s    width
  IL_0027:  br.s       IL_0036
  IL_0029:  ldstr      "80%"
  IL_002e:  stloc.3
  IL_002f:  ldstr      "80%"
  IL_0034:  stloc.s    width
  IL_0036:  ldc.i4.5
  IL_0037:  newarr     [mscorlib]System.String
  IL_003c:  stloc.s    CS$0$0000
  IL_003e:  ldloc.s    CS$0$0000
  IL_0040:  ldc.i4.0
  IL_0041:  ldstr      "Height: "
  IL_0046:  stelem.ref
  IL_0047:  ldloc.s    CS$0$0000
  IL_0049:  ldc.i4.1
  IL_004a:  ldloc.3
  IL_004b:  stelem.ref
  IL_004c:  ldloc.s    CS$0$0000
  IL_004e:  ldc.i4.2
  IL_004f:  call       string [mscorlib]System.Environment::get_NewLine()
  IL_0054:  stelem.ref
  IL_0055:  ldloc.s    CS$0$0000
  IL_0057:  ldc.i4.3
  IL_0058:  ldstr      "Width: "
  IL_005d:  stelem.ref
  IL_005e:  ldloc.s    CS$0$0000
  IL_0060:  ldc.i4.4
  IL_0061:  ldloc.s    width
  IL_0063:  stelem.ref
  IL_0064:  ldloc.s    CS$0$0000
  IL_0066:  call       string [mscorlib]System.String::Concat(string[])
  IL_006b:  stloc.1
  IL_006c:  ldloc.2
  IL_006d:  ldc.i4.1
  IL_006e:  add
  IL_006f:  stloc.2
  IL_0070:  ldloc.2
  IL_0071:  ldc.i4     0xf4240
  IL_0076:  blt.s      IL_0016
  IL_0078:  ldloc.0
  IL_0079:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_007e:  ldstr      "testifelse.txt"
  IL_0083:  ldloc.1
  IL_0084:  call       void [mscorlib]System.IO.File::WriteAllText(string,
                                                                   string)
  IL_0089:  ldloc.0
  IL_008a:  callvirt   instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
  IL_008f:  ret
} // end of method frmResearch::WithIfAndElse

塊#2

.method public hidebysig instance int64  WithOnlyIf(int32 myFlag) cil managed
{
  // Code size       142 (0x8e)
  .maxstack  3
  .locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,
           [1] string someString,
           [2] int32 i,
           [3] string height,
           [4] string width,
           [5] string[] CS$0$0000)
  IL_0000:  newobj     instance void [System]System.Diagnostics.Stopwatch::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldstr      ""
  IL_000b:  stloc.1
  IL_000c:  ldloc.0
  IL_000d:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Start()
  IL_0012:  ldc.i4.0
  IL_0013:  stloc.2
  IL_0014:  br.s       IL_006e
  IL_0016:  ldstr      "80%"
  IL_001b:  stloc.3
  IL_001c:  ldstr      "80%"
  IL_0021:  stloc.s    width
  IL_0023:  ldarg.1
  IL_0024:  ldc.i4.1
  IL_0025:  bne.un.s   IL_0034
  IL_0027:  ldstr      "60%"
  IL_002c:  stloc.3
  IL_002d:  ldstr      "60%"
  IL_0032:  stloc.s    width
  IL_0034:  ldc.i4.5
  IL_0035:  newarr     [mscorlib]System.String
  IL_003a:  stloc.s    CS$0$0000
  IL_003c:  ldloc.s    CS$0$0000
  IL_003e:  ldc.i4.0
  IL_003f:  ldstr      "Height: "
  IL_0044:  stelem.ref
  IL_0045:  ldloc.s    CS$0$0000
  IL_0047:  ldc.i4.1
  IL_0048:  ldloc.3
  IL_0049:  stelem.ref
  IL_004a:  ldloc.s    CS$0$0000
  IL_004c:  ldc.i4.2
  IL_004d:  call       string [mscorlib]System.Environment::get_NewLine()
  IL_0052:  stelem.ref
  IL_0053:  ldloc.s    CS$0$0000
  IL_0055:  ldc.i4.3
  IL_0056:  ldstr      "Width: "
  IL_005b:  stelem.ref
  IL_005c:  ldloc.s    CS$0$0000
  IL_005e:  ldc.i4.4
  IL_005f:  ldloc.s    width
  IL_0061:  stelem.ref
  IL_0062:  ldloc.s    CS$0$0000
  IL_0064:  call       string [mscorlib]System.String::Concat(string[])
  IL_0069:  stloc.1
  IL_006a:  ldloc.2
  IL_006b:  ldc.i4.1
  IL_006c:  add
  IL_006d:  stloc.2
  IL_006e:  ldloc.2
  IL_006f:  ldc.i4     0xf4240
  IL_0074:  blt.s      IL_0016
  IL_0076:  ldloc.0
  IL_0077:  callvirt   instance void [System]System.Diagnostics.Stopwatch::Stop()
  IL_007c:  ldstr      "testif.txt"
  IL_0081:  ldloc.1
  IL_0082:  call       void [mscorlib]System.IO.File::WriteAllText(string,
                                                                   string)
  IL_0087:  ldloc.0
  IL_0088:  callvirt   instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
  IL_008d:  ret
} // end of method frmResearch::WithOnlyIf

所以我們可以說IF-Else塊(塊#1)比if塊(塊#2)運行得更快,正如本論壇中許多人所指出的那樣。




更快的方法是將高度和寬度視為整數/浮點數並在最後一秒將它們轉換為字符串...假設您經常執行此操作以遠程重要(提示:您不是)。




我會使用Block#2 。 正如你所說,性能影響可以忽略不計,但它肯定更短更容易閱讀。 實際上,除非滿足特定條件,否則您將為變量設置默認值。




糾正結果。 我做了自己的測試,我發現這個值我覺得更準確。 迭代次數:100,000,000

標誌= 1

標誌= 0。

事實上,更糟糕的案件時間應該是最佳案件的兩倍是錯誤的。

使用的代碼

string height;
string width;
int myFlag = 1;

Console.WriteLine(" ----------- case 1 ---------------");
DateTime Start = DateTime.Now;
for (int Lp = 0; Lp < 100000000; Lp++)
{

    if (myFlag == 1)
    {
        height = "60%";
        width = "60%";
    }
    else
    {
        height = "80%";
        width = "80%";
    }          

}

TimeSpan Elapsed = DateTime.Now - Start;
Console.WriteLine("Time Elapsed: {0} ms",Elapsed.Milliseconds);

Console.WriteLine(" ----------- case 2 ---------------");

DateTime Start2 = DateTime.Now;
for (int Lp = 0; Lp < 100000000; Lp++)
{

    height = "80%";
    width = "80%";

    if (myFlag == 1)
    {
        height = "60%";
        width = "60%";
    }
}

    Elapsed = DateTime.Now - Start2;
    Console.WriteLine("Time Elapsed: {0} ms", Elapsed.Milliseconds);



您可以使用性能分析器自己回答這個問題,或者只是計時(將函數放在您多次調用的循環中)。 如您所知,編譯器將其轉換為相同的代碼(您可以檢查)

可能你不應該擔心這些微觀優化。 編寫最易讀的代碼,直到您的工具告訴您要優化的內容。




我通常使用Block#2方法,因為我知道有問題的變量最初設置為默認值




Related