簡體   English   中英

C#編譯器優化

[英]C# Compiler Optimization

為什么編譯器會優化我的代碼?

我有2個功能:

public void x1() {
  x++;
  x++;
}
public void x2() {
  x += 2;
}
public void x3() {
  x = x + 2;
}
public void y3() {
  x = x * x + x * x;
}

這是我在發布模式下編譯后可以看到的ILSpy:

// test1.Something
public void x1()
{
    this.x++;
    this.x++;
}

// test1.Something
public void x2()
{
    this.x += 2;
}
// test1.Something
public void x3()
{ 
    this.x += 2;
}
// test1.Something
public void y3()
{
    this.x = this.x * this.x + this.x * this.x;
}

x2和x3可能沒問題。 但是為什么x1沒有針對相同的結果進行優化? 沒有理由保持兩步增量? 為什么y3不是x=2*(x*x) 不應該比x*x+x*x快嗎?

這導致了這個問題? 如果沒有這么簡單的事情,C#編譯器會進行什么樣的優化?

當我閱讀有關編寫您經常聽到的代碼的文章時,將其寫為可讀,編譯器將完成其余的工作。 但在這種情況下,編譯器幾乎什么也沒做。


再添一個例子:

public void x1() {
  int a = 1;
  int b = 1;
  int c = 1;
  x = a + b + c;
}

並使用ILSpy:

// test1.Something
public void x1()
{
    int a = 1;
    int b = 1;
    int c = 1;
    this.x = a + b + c;
}

為什么不是這個。= 3?

如果不假設變量x不與運行方法同時訪問,則編譯器無法執行此優化。 否則,可能會以可檢測的方式更改方法的行為。

考慮從兩個線程同時訪問this引用的對象的情況。 Tread A重復將x設置為零; 線程B反復調用x1()

如果編譯器將x1優化為x2的等效值,則實驗后x的兩個可觀察狀態將為02

  • 如果AB之前結束,你得到2
  • 如果BA之前結束,則得到0

如果A在中間搶占B ,你仍然會獲得2

然而,原始版本x1允許三個結果: x可以最終被01 ,或2

  • 如果AB之前結束,你得到2
  • 如果BA之前結束,則得到0
  • 如果B在第一個增量后被搶占,那么A結束,然后B運行完成,你得到1

x1x2不一樣:

如果x是一個公共字段並且是在多線程環境中訪問的,那么第二個線程完全有可能在兩個調用之間改變x ,這對於x2的代碼是不可能的。

對於y2 ,如果+和/或*x的類型重載,那么x*x + x*x 可能不同於 2*x*x

編譯器會優化像(不是詳盡無遺的列表):

  • 刪除未使用的局部變量(釋放寄存器)
  • 刪除不影響邏輯流程或輸出的代碼。
  • 內聯對簡單方法的調用

編譯器優化不應該改變程序的行為(盡管確實發生了)。 因此重新排序/組合數學運算超出了優化范圍。

寫它可讀,編譯器將完成剩下的工作。

好吧,編譯器可能會做一些優化,但仍然有很多工作可以在設計時提高性能。 是可讀代碼絕對有價值,但編譯器的工作是生成與源代碼相對應的工作 IL,而不是更快地更改源代碼。

暫無
暫無

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

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