[英]Will the C# compiler optimize this code?
我經常遇到這種情況。 乍一看,我認為,“這是糟糕的編碼; 我正在執行一個方法兩次並且必然會得到相同的結果。“但是在想到這一點時,我不得不懷疑編譯器是否像我一樣聰明並且可以得出相同的結論。
var newList = oldList.Select(x => new Thing {
FullName = String.Format("{0} {1}", x.FirstName, x.LastName),
OtherThingId = x.GetOtherThing() != null : x.GetOtherThing().Id : 0 // Might call x.GetOtherThing() twice?
});
編譯器的行為是否依賴於GetOtherThing
方法的內容? 說它看起來像這樣(有點類似於我現在的真實代碼):
public OtherThing GetOtherThing() {
if (this.Category == null) return null;
return this.Category.OtherThings.FirstOrDefault(t => t.Text == this.Text);
}
這將禁止對這些對象來自的任何商店進行非常糟糕的異步更改,如果連續運行兩次,肯定會返回相同的內容。 但如果它看起來像這樣(為了論證而荒謬的例子):
public OtherThing GetOtherThing() {
return new OtherThing {
Id = new Random().Next(100)
};
}
連續兩次運行將導致創建兩個不同的對象,並且很可能具有不同的ID。 編譯器在這些情況下會做什么? 它是否像我在第一個清單中所展示的那樣低效?
我運行了與第一個代碼清單非常相似的東西,並在 GetOtherThing
實例方法中放置了一個斷點。斷點被擊中一次。 所以,看起來結果確實是緩存的。 在第二種情況下會發生什么,該方法可能每次返回不同的東西? 編譯器會不正確地優化? 我發現結果有什么警告嗎?
編輯
那個結論無效。 請參閱@ usr的答案下的評論。
這里有兩個編譯器需要考慮:將C#轉換為IL的C#編譯器,以及將IL轉換為機器代碼的IL編譯器 - 稱為抖動,因為它恰好發生在時間上。
Microsoft C#編譯器肯定沒有這樣的優化。 方法調用生成為方法調用,故事結束。
允許抖動執行您描述的優化, 前提是無法檢測到這種情況 。 例如,假設你有:
y = M() != 0 ? M() : N()
和
static int M() { return 1; }
允許抖動將此程序轉換為:
y = 1 != 0 ? 1 : N()
或者就此而言
y = 1;
抖動是否這樣做是一個實現細節; 如果你關心的話,你將不得不向專家詢問抖動是否確實會執行此優化。
同樣,如果你有
static int m;
static int M() { return m; }
那么抖動可以將其優化成
y = m != 0 ? m : N()
甚至進入:
int q = m;
y = q != 0 ? q : N();
因為只要該字段不是易失性的,就允許抖動連續轉換兩個字段讀取而不插入單個字段讀取。 無論它是否這樣做都是一個實現細節; 問一個抖動的開發人員。
但是,在后一個例子中,抖動不能忽略第二次調用,因為它有副作用。
我運行了與第一個代碼清單非常相似的東西,並在GetOtherThing實例方法中放置了一個斷點。 斷點被擊中一次。
這是非常不可能的。 在調試時幾乎所有優化都會被關閉,這樣就可以更容易地進行調試。 正如福爾摩斯從未說過的那樣 ,當你消除不可能的事情時,最可能的解釋是原來的海報是錯誤的。
如果您無法區分,編譯器只能應用優化。 在您的“隨機”示例中,您可以清楚地區分出來。 它不能以這種方式“優化”。 它會違反C#規范。 事實上,該規范並未談及優化問題。 它只是說你應該觀察程序做什么。 在這種情況下,它指定應繪制兩個隨機數。
在第一個示例中,可以應用此優化。 它在實踐中永遠不會發生。 以下是一些令人困難的事情:
t => t.Text == this.Text
)可以更改列表。 非常陰險。 所有這些都必須適用於非內聯方法和跨程序集。
C#編譯器無法執行此操作,因為它無法查看mscorlib。 修補程序版本可能隨時更改mscorlib。
JIT是一個糟糕的JIT(唉),它針對編譯速度進行了優化(唉)。 它沒有這樣做。 如果您懷疑當前的JIT是否會進行一些高級優化,那么可以肯定它不會。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.