相信很多.NETer看了標題,都會忍不住好奇,點進來看看,並且順便準備要噴作者! 這裡,首先要申明一下,作者本人也非常喜歡Linq,也在各個項目中常用Linq。 我愛Linq,Linq優雅萬歲!!!(PS:順便吐槽一下,隔壁Java從8.0版本推出的Streams API,抄了個四不像,一點都不優雅 ...
相信很多.NETer看了標題,都會忍不住好奇,點進來看看,並且順便準備要噴作者!
這裡,首先要申明一下,作者本人也非常喜歡Linq,也在各個項目中常用Linq。
我愛Linq,Linq優雅萬歲!!!(PS:順便吐槽一下,隔壁Java從8.0版本推出的Streams API,抄了個四不像,一點都不優雅,而且很難用。
)
正文
不羅嗦,就一句話:“在性能敏感型應用和追求零記憶體分配場景不推薦使用Linq!
”
讓我們用Benchmark結果來說話!!!
這裡用一個簡單的場景來驗證:
- 拆分一個String字元串為String[]數組。
- 轉換數組中的每個String字元串為Int32數值。
- 對這些數值求和。
讓我們通過BenchmarkDotNet運行性能測試,看看用Linq和不用Linq,這兩者之間的性能差異。
Benchmark代碼:
internal class Program
{
static void Main(string[] args)
{
BenchmarkRunner.Run<LinqTest>();
Console.ReadKey();
}
}
[MemoryDiagnoser, MemoryRandomization]
public class LinqTest
{
private static readonly string _row = "1,2,3,4,5,6,7,8,9,10";
[Benchmark]
public void SumUsingLinq()
{
int sum = _row.Split(',').Select(int.Parse).Sum();
}
[Benchmark(Baseline = true)]
public void SumUsingForLoop()
{
var rowSpan = _row.AsSpan();
int sum = 0;
for (int i = 0; i < rowSpan.Length; i++)
{
if (rowSpan[i] == ',')
{
sum += int.Parse(rowSpan.Slice(0, i));
rowSpan = rowSpan.Slice(i + 1);
i = 0;
}
}
}
}
Benchmark結果:
從結果中,我們可以看到,不使用Linq的SumUsingForLoop方法,Mean平均值 75.09 ns,Allocated 無;
反觀使用了Linq的SumUsingLinq方法,Mean平均值 270.18 ns,Allocated 400 B;
兩者之間有約3.5倍的性能差距,而記憶體分配表現方面也是不使用Linq的占優。
總結:
對於追求 零記憶體分配(zero-copy)目標 或者 速度敏感型應用,這兩種場景,都應該慎用Linq。因為Linq擴展方法里有大量的判斷,甚至還有很多內部對象的創建和記憶體開銷。
PS: 想要堅持寫技術文章、寫博客、寫公眾號,真的很難。
2024-06-26 更新
很多人覺得這個對比不公平:
- 不應該用Spilt,
- 不應該調用Select,可以把Parse放到Sum方法里處理。
經過網友調整代碼後,再次測試下來,也依然有少量的記憶體分配,32B,Mean平均值依然相差18ns左右。
以下是網友修改代碼後的測試結果
出處:http://www.cnblogs.com/vallen
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
唯有偏執者得以生存。