其中 lambda 與第一個 lambda
假設我有一些字元串:
string[] strings = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };有什麼區別:
string startsWithO = strings.First(s => s[0] == 'o');和:
string startsWithO = strings.Where(s => s[0] == 'o').First();由於 Where() 被推遲,它不應該減慢執行速度,對吧?
.Where(filter).First()使用而不是使用的性能損失.First(filter)通常非常小。然而,它們並不相同——
Where生成一個新的迭代器,它First可以簡單地獲取一個元素,而First(filter)可以通過只使用一個循環和filter匹配時直接返回來進行微優化。因此,雖然這兩種方法具有相同的語義並且都
filter同樣頻繁地執行(僅在必要時執行),但使用Firstwithfilter參數不需要創建中間迭代器對象,並且可能也避免了對該迭代器的一些非常簡單的方法呼叫。換句話說,如果你正在執行這樣的程式碼數百萬次,你會看到輕微的性能差異——但沒什麼大不了的;我永遠不會擔心它。每當這種微小的性能差異實際上很重要時,您最好只編寫等效的(非常簡單的)foreach-with-if 語句並避免 LINQ 中固有的額外呼叫和對象分配 - 但請記住,這是一個微優化,您將很少需要。
**編輯:**基準展示效果:
這需要 0.78 秒:
for(int i=0;i<10*1000*1000;i++) Enumerable.Range(0,1000).First(n=> n > 2); GC.Collect();但這需要 1.41 秒:
for(int i=0;i<10*1000*1000;i++) Enumerable.Range(0,1000).Where(n=> n > 2).First(); GC.Collect();而普通循環要快得多(0.13 秒):
long bla = 0; for(int i=0;i<10*1000*1000;i++) for(int n=0;n<1000;n++) if(n > 2) { bla+=n; break; } GC.Collect(); Console.WriteLine(bla);//avoid optimizer cheating.請注意,此基準僅顯示如此極端的差異,因為我有一個微不足道的過濾器和一個非常短的不匹配前綴。
基於一些快速的實驗,差異似乎很大程度上歸因於採用哪個程式碼路徑的細節。因此,對於數組和
List<>s,第一個變體實際上更快,可能.Where對那些沒有的類型進行特殊處理First;對於自定義迭代器,第二個版本比預期的要快一點。概括:
.Where(...).First()大致與.First(...)- 不要費心選擇一個或另一個作為優化一樣快。一般來說*,*.First(...)速度會稍微快一些,但在某些常見情況下會更慢。如果你真的需要微優化,那麼使用比任何一個都快的普通循環。