[英]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
的兩個可觀察狀態將為0
和2
:
A
在B
之前結束,你得到2
B
在A
之前結束,則得到0
如果A
在中間搶占B
,你仍然會獲得2
。
然而,原始版本x1
允許三個結果: x
可以最終被0
, 1
,或2
。
A
在B
之前結束,你得到2
B
在A
之前結束,則得到0
B
在第一個增量后被搶占,那么A
結束,然后B
運行完成,你得到1
。 x1
和x2
不一樣:
如果x
是一個公共字段並且是在多線程環境中訪問的,那么第二個線程完全有可能在兩個調用之間改變x
,這對於x2
的代碼是不可能的。
對於y2
,如果+
和/或*
為x
的類型重載,那么x*x + x*x
可能不同於 2*x*x
。
編譯器會優化像(不是詳盡無遺的列表):
編譯器優化不應該改變程序的行為(盡管確實發生了)。 因此重新排序/組合數學運算超出了優化范圍。
寫它可讀,編譯器將完成剩下的工作。
好吧,編譯器可能會做一些優化,但仍然有很多工作可以在設計時提高性能。 是可讀代碼絕對有價值,但編譯器的工作是生成與源代碼相對應的工作 IL,而不是更快地更改源代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.