Dot-Net
為什麼 F# inline 會導致 11 倍的性能提升
我正在處理一些繁重的 cpu 綁定問題。當我使用
inline關鍵字時,我看到了很大的性能改進。我從標準 .net 庫中創建了一個字典,傳入了一個自定義鍵比較器,請參見下面的程式碼和計時結果<https://gist.github.com/4409734>
在 Eq_cmp 上沒有內聯關鍵字
> perf_run 10000000 ;; Real: 00:00:11.039, CPU: 00:00:11.029, GC gen0: 771, gen1: 3, gen2: 1 val it : unit = ()在 Eq_cmp 上使用 inline 關鍵字
perf_run 10000000 ;; Real: 00:00:01.319, CPU: 00:00:01.388, GC gen0: 1, gen1: 1, gen2: 1 val it : unit = () >我還注意到 Gen 0 GC 的數量與內聯程式碼和非內聯程式碼的巨大差異。
有人可以解釋為什麼會有如此巨大的差異嗎?
inline添加關鍵字後,我可以通過 3 倍的性能提升來重現我的機器上的行為。在ILSpy下並排反編譯兩個版本會得到幾乎相同的 C# 程式碼。顯著的區別在於兩個相等測試:
// Version without inline bool IEqualityComparer<Program.Pair<a>>.System-Collections-Generic-IEqualityComparer(Program.Pair<a> x, Program.Pair<a> y) { a v@ = x.v@; a v@2 = y.v@; if (LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<a>(v@, v@2)) { a w@ = x.w@; a w@2 = y.w@; return LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<a>(w@, w@2); } return false; } // Version with inline bool IEqualityComparer<Program.Pair<int>>.System-Collections-Generic-IEqualityComparer(Program.Pair<int> x, Program.Pair<int> y) { int v@ = x.v@; int v@2 = y.v@; if (v@ == v@2) { int w@ = x.w@; int w@2 = y.w@; return w@ == w@2; } return false; }泛型相等的效率遠低於專門的版本。
我還注意到 Gen 0 GC 的數量與內聯程式碼和非內聯程式碼的巨大差異。
有人可以解釋為什麼會有如此巨大的差異嗎?
看一下F# 原始碼
GenericEqualityIntrinsic中的函式:let rec GenericEqualityIntrinsic (x : 'T) (y : 'T) : bool = fsEqualityComparer.Equals((box x), (box y))它對參數進行裝箱,這解釋了您的第一個範例中的大量垃圾。當 GC 過於頻繁地發揮作用時,它會顯著減慢計算速度。第二個範例(使用)在struct
inline時幾乎不會產生垃圾。Pair也就是說,
inline在呼叫站點使用專用版本時,這是關鍵字的預期行為。我的建議是始終嘗試在相同的基准上優化和衡量您的程式碼。您可能對一個非常相似的執行緒感興趣為什麼這個 F# 程式碼這麼慢?.