之前在網路上看到有人說可以用 Any() 取代 Count()==0 ,效能會比較好,畢竟 Count()==0
平常寫得很習慣,一開始我以為這只是誤差,沒想到背後居然真有明顯的效能差異,於是我動手測一下..
1. 建立兩個 function 一個是用 Any() 判斷,一個是用 Count() 判斷,裡面比較需要注意的就是 如果沒有使用 Where
GPT表示:
Enumerable.Range(0, 10) 會回傳一個內建的 Range 迭代器。
在 .NET 裡,Count() 會先嘗試「不枚舉就拿到總數」的捷徑(例如 ICollection<T>.Count、內建迭代器的快速路徑、或 TryGetNonEnumeratedCount)。
對 Range 這種來源,總數是已知的,所以 Count() 不需要跑 foreach 就能知道答案(10)。
public static void AnyPerformance(int i) {
IEnumerable src;
if (i % 2 == 0)
{
src = Enumerable.Range(0, 10).Where(x => x > -1);
}
else
{
src = Enumerable.Empty();
}
bool emptyByCount = src.Any();
}
public static void CountPerformance(int i)
{
IEnumerable src;
if (i % 2 == 0)
{
src = Enumerable.Range(0, 10).Where(x=>x>-1);
}
else
{
src = Enumerable.Empty();
}
bool emptyByCount = src.Count() == 0;
}
2. 之後就是主程式分別測試 一千萬次然後計算時間
var sw = Stopwatch.StartNew();
for (var i = 1; i <= 10_000_000; i++) {
AnyPerformance(i);
}
Console.WriteLine($"!Any(): {sw.ElapsedMilliseconds} ms");
var sw1 = Stopwatch.StartNew();
for (var i = 1; i <= 10_000_000; i++)
{
CountPerformance(i);
}
Console.WriteLine($"Count() == 0: {sw1.ElapsedMilliseconds} ms");
結果:
!Any(): 641 ms
Count() == 0: 1185 ms
!Any(): 570 ms
Count() == 0: 1078 ms
!Any(): 594 ms
Count() == 0: 1086 ms
結論:
簡單的說,如果你只要判斷那個集合是不是沒有東西,直接用 Any() 因為他的記憶體指標只檢查一個就離開了
如果你使用 Count() 他為了給你精準的數字,但是你偏偏只是要判斷是不是 沒有東西,就有點殺雞焉用核彈
一個不被注意的小事情,因為連我也是常常因為很直覺就寫了 Count()==0 這點要改改了。