2012-06-01 54 views
4

這就是我想做的事:編譯器是否會針對布爾分配進行優化?

if(ABoolean || (BBoolean && CBoolean)) 
{ 
    SomeButton.Enabled = true; 
    AnotherButton.Enabled = true; 
} 
else 
{ 
    SomeButton.Enabled = false; 
    AnotherButton.Enabled = false; 
} 

我可以切換這:

SomeButton.Enabled = (ABoolean || (BBoolean && CBoolean)); 
AnotherButton.Enabled = (ABoolean || (BBoolean && CBoolean)); 

對於一個更簡潔的代碼。我的問題是,編譯器是否優化了賦值,使其能夠看到布爾表達式是相同的,併爲第二個按鈕賦值,或者每次都會計算該值。

注意:我知道這是一個簡單的例子,加速/減速對於不重要的地方來說是微不足道的,但它有助於我更好地理解編譯器優化。

編輯:這就是爲什麼我認爲第二個選項可能被優化的原因:

class Program 
{ 
    static bool ABoolean = true, BBoolean = true, CBoolean = false; 
    static bool AEnable, BEnable; 


    static void Main(string[] args) 
    { 
     Stopwatch sw = new Stopwatch(); 
     sw.Start(); 
     for (int i = 0; i < 1000000000; i++) 
     { 
      Operation1(); 
     } 
     sw.Stop(); 
     Console.WriteLine(sw.ElapsedMilliseconds); 

     Stopwatch sw1 = new Stopwatch(); 
     sw1.Start(); 
     for (int i = 0; i < 1000000000; i++) 
     { 
      Operation2(); 
     } 
     sw1.Stop(); 
     Console.WriteLine(sw1.ElapsedMilliseconds); 
     Console.Read(); 
    } 

    static void Operation1() 
    { 
     if (ABoolean || (BBoolean && CBoolean)) 
     { 
      AEnable = true; 
      BEnable = true; 
     } 
     else 
     { 
      AEnable = false; 
      BEnable = false; 
     } 
    } 

    static void Operation2() 
    { 
     AEnable = (ABoolean || (BBoolean && CBoolean)); 
     BEnable = (ABoolean || (BBoolean && CBoolean)); 
    } 
} 

這導致大約〜8-9超過1個十億操作第二差(與第二個選項運行速度更快)。正如我添加更多「啓用」布爾值,但第二個操作變得更慢。

+3

順便說一句:第三種方式是通過變量賦值:'VAR啓用=(ABoolean ||( BBoolean && CBool​​ean))',然後使用該變量來設置'.Enabled'屬性。 – CAbbott

回答

7

不,我不希望編譯器優化。這可能是因爲它可以優化(因爲它有更多的信息),但我不希望C#編譯器能夠。

如何可以在編譯器知道SomeButton.Enabled是否會有一些副作用,這可能改變ABooleanBBooleanCBoolean價值?

編輯:驗證這個...讓我們給C#編譯器的絕對最機會:通過ILDASM

csc /o+ /debug- Test.cs 

代碼Foo

class Test 
{ 
    static void Main() 
    { 
     Foo(true, false, true); 
    } 

    static void Foo(bool x, bool y, bool z) 
    { 
     A = x || (y && z); 
     B = x || (y && z); 
    } 

    static bool A { get; set; } 
    static bool B { get; set; } 
} 

編譯

.method private hidebysig static void Foo(bool x, 
              bool y, 
              bool z) cil managed 
{ 
    // Code size  37 (0x25) 
    .maxstack 8 
    IL_0000: ldarg.0 
    IL_0001: brtrue.s IL_000c 
    IL_0003: ldarg.1 
    IL_0004: brfalse.s IL_0009 
    IL_0006: ldarg.2 
    IL_0007: br.s  IL_000d 
    IL_0009: ldc.i4.0 
    IL_000a: br.s  IL_000d 
    IL_000c: ldc.i4.1 
    IL_000d: call  void Test::set_A(bool) 
    IL_0012: ldarg.0 
    IL_0013: brtrue.s IL_001e 
    IL_0015: ldarg.1 
    IL_0016: brfalse.s IL_001b 
    IL_0018: ldarg.2 
    IL_0019: br.s  IL_001f 
    IL_001b: ldc.i4.0 
    IL_001c: br.s  IL_001f 
    IL_001e: ldc.i4.1 
    IL_001f: call  void Test::set_B(bool) 
    IL_0024: ret 
} // end of method Test::Foo 

正如你所看到的,表達真在兩種情況下都被評估。

+0

感謝這個答案,我感到困惑,因爲我實際上計時了這兩個選項,並且第二個選項獲得了顯着更快的結果。我假設這是由於if/else子句的開銷。因此,在第二種情況下,布爾操作的數量應該有一個不返回的結果,導致時間減慢的權利? – NominSim

+0

@NominSim:我不希望*版本顯着更快*。我懷疑你的診斷:)但是,真的,這可能是整體上對你而言甚至稍微重要嗎? –

+0

超過10億次操作的差異是〜8秒(〜19 vs〜11)...我認爲重要的是主觀的,當我增加5個布爾分配時,第二個選項變得更慢。絕對沒有什麼重要意義,我只是解釋了我最初得出的結論是它可能會優化第二個版本。 – NominSim

4

我的問題是,編譯器是否優化了賦值,使得它看到布爾表達式是相同的,併爲第二個按鈕賦值,或者每次都會計算它的值。

它會每次計算值。

如果這是一個多線程應用程序會怎麼樣?其他一些線程可能會改變它。

如果它們不是常量變量,則可以更改它們。

要優化你可以做

SomeButton.Enabled = AnotherButton.Enabled = (ABoolean || (BBoolean && CBoolean)); 

在這種情況下,它會被計算一次和價值首先分配給AnotherButton第一和SomeButton更高版本。記住它在分配中的權利。

+0

沒錯。因爲這些是涉及非常量變量的兩個單獨的語句。所以編譯器在這裏不能假設任何東西。這兩個語句之間的變量可能會發生變化,特別是如果您的應用程序是多線程的。 –

+3

現在你只是從別人的答案中獲取細節。這很滑稽。但我不確定你發佈的內容是否是真正的優化。布爾評估*非常快*。我認爲引用屬性的'get'訪問器通常具有與調用內聯方法相同的開銷。所以這可能很容易比原始代碼慢。雖然,我們正在談論納秒,但仍然是。 –

+0

@SteveWortham:是的,我承認我複製了它。但不是來自某人的回答,而是來自我的大腦。 –

2

沒有,編譯器不會優化它在我的經驗,但是,你可以這樣做:

SomeButton.Enabled = AnotherButton.Enabled = (ABoolean || (BBoolean && CBoolean)); 
相關問題