从List中查找元素,Find与FirstOrDefault孰优孰劣?

时间:09/17/2024 00:02:20   作者:ChenReal    阅读:30

image.png

上面这张图片,是今天波波同学发给我的。刚看到图片内容的瞬间,我不禁一惊。因为,在我写的代码中FindFirstOrDefault都曾用到,并且在我的概念里两者几乎都是等价的,并没有本质上的区别。今天看人家还有提供测试数据,似乎我应该将FirstOrDefault全部都换成Find才是最优的解。

仔细回想了一下,很久之前也曾经在StackOverFlow的一个帖子上读到过,类似的讨论。其结论也是Find表现出的性能,会大大优于FirstOrDefault。我把原帖搜索出来了:

https://stackoverflow.com/questions/14032709/performance-of-find-vs-firstordefault

发现这竟然是10多年前的帖子!拜托,那时候还是.NET Framework的天下,连.NET Core 1.0都还没有呢!今天已经就快步入.NET9的时代。这个结论还成立吗?

既然有所怀疑,不如来个实实在在的测试。论证一下,在今天FirstOrDefaultFind是否还存在如此大的差距。

编写测试代码

首先,创建一个.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();
Console.WriteLine(summary); } ```

结果

运行基准测试,几分钟后得到结果如图:

image.png

从结果来看Find确实比FirstOrDefault执行效率略高一些,如果代码里的选择是用Find似乎还是比较明智的。然而,两个方法之间性能差异数值并不算很大,大约在3-10%之间。

因此,我的结论是能用Find尽量用Find,但如果代码已经用了FirstOrDefault也不是什么灾难性的问题,所以不用恐慌,也不必急于马上改过来。淡定自若就可以了。

最后,我还顺带介绍了BenchmarkDotNet作为性能测试框架的使用方法。这也是个一个知识点哦,希望小伙伴们都能Get到~

 

评论
0/200