上面这张图片,是今天波波同学发给我的。刚看到图片内容的瞬间,我不禁一惊。因为,在我写的代码中Find
和FirstOrDefault
都曾用到,并且在我的概念里两者几乎都是等价的,并没有本质上的区别。今天看人家还有提供测试数据,似乎我应该将FirstOrDefault
全部都换成Find
才是最优的解。
仔细回想了一下,很久之前也曾经在StackOverFlow的一个帖子上读到过,类似的讨论。其结论也是Find
表现出的性能,会大大优于FirstOrDefault
。我把原帖搜索出来了:
https://stackoverflow.com/questions/14032709/performance-of-find-vs-firstordefault
发现这竟然是10多年前的帖子!拜托,那时候还是.NET Framework的天下,连.NET Core 1.0都还没有呢!今天已经就快步入.NET9的时代。这个结论还成立吗?
既然有所怀疑,不如来个实实在在的测试。论证一下,在今天FirstOrDefault
和Find
是否还存在如此大的差距。
编写测试代码
首先,创建一个.NET8的控制台项目。
dotnet new console -o TestListApp
接着,nuget引入性能测试框架Benchmark.NET
。
dotnet add package BenchmarkDotNet
最后开始写代码进行测试:
- 新建一个
ListTest.cs
类文件,然后编写基准测试代码。
[MemoryDiagnoser]
public class ListTest
{
[Benchmark]
public int? TestFindInt()
{
var list = new List<int>(5000);
for (int i = 0; i < 5000; i++)
{
list.Add(i);
}
return list.Find(i => i > 1200);
}
[Benchmark]
public int? TestFirstInt()
{
var list = new List<int>(5000);
for (int i = 0; i < 5000; i++)
{
list.Add(i);
}
return list.FirstOrDefault(i => i > 1200);
}
[Benchmark]
public object? TestFindObject()
{
var list = new List<Student>(5000);
for (int i = 0; i < 5000; i++)
{
list.Add(new Student()
{
Id = i + 1,
Name = "Student" + i,
Age = i % 4 + 18
});
}
return list.Find(o => o.Id == 339);
}
[Benchmark]
public object? TestFirstObject()
{
var list = new List<Student>(5000);
for (int i = 0; i < 5000; i++)
{
list.Add(new Student()
{
Id = i+1,
Name="Student"+i,
Age = i%4 + 18
});
}
return list.FirstOrDefault(o => o.Id==339);
}
}
class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
- 打开
Program.cs
文件,添加以下代码:
internal class Program
{
var summary = BenchmarkRunner.Run<ListTest>();
Console.WriteLine(summary);
}
结果
运行基准测试,几分钟后得到结果如图:
从结果来看Find
确实比FirstOrDefault
执行效率略高一些,如果代码里的选择是用Find
似乎还是比较明智的。然而,两个方法之间性能差异数值并不算很大,大约在3-10%之间。
因此,我的结论是能用Find
尽量用Find
,但如果代码已经用了FirstOrDefault
也不是什么灾难性的问题,所以不用恐慌,也不必急于马上改过来。淡定自若就可以了。
最后,我还顺带介绍了BenchmarkDotNet
作为性能测试框架的使用方法。这也是个一个知识点哦,希望小伙伴们都能Get到~