还记得我们当初在代码审查中从Exists()转向Any(),因为"LINQ是未来"吗?然后花了数年时间争论微观优化?让我们聊聊为什么在.NET 9中这个争论变得简单多了。
在.NET 6-8时代,性能层级非常清晰:
Exists(): List
Any(): 灵活但缓慢
适用于所有IEnumerable
开发者们将这些经验教条般地植入代码库:
"处理List
.NET 9运行时引入了多项有利于Any()的关键改进:
LINQ方法内联 JIT编译器现在能积极内联像Any()这样的简单LINQ方法,减少虚方法调用开销,使Any()基础性能更接近直接方法调用。
基于Span的优化 改进的Span处理使Any()在可能情况下为数组和列表使用优化路径,避免完整IEnumerable枚举:
// .NET 9内部实现示意
public static bool Any<T>(this List<T> list, Func<T, bool> predicate)
{
foreach (ref readonly var item in CollectionsMarshal.AsSpan(list))
{
if (predicate(item)) return true;
}
return false;
}
让我们看看在.NET 9中的测试设置和结果对比
测试设置:
using System;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
public class AnyVsExistsBenchmark
{
private List<int> _list;
private int[] _array;
private IEnumerable<int> _enumerable;
[Params(10, 1000, 1_000_000)]
public int CollectionSize { get; set; }
[GlobalSetup]
public void Setup()
{
var random = new Random();
_list = Enumerable.Range(0, CollectionSize)
.Select(_ => random.Next(0, 10000))
.ToList();
_array = _list.ToArray();
_enumerable = _list.Select(x => x);
}
[Benchmark(Description = "List.Any()")]
public bool ListAny() => _list.Any(x => x > 5000);
[Benchmark(Description = "List.Exists()")]
public bool ListExists() => _list.Exists(x => x > 5000);
[Benchmark(Description = "Array.Any()")]
public bool ArrayAny() => _array.Any(x => x > 5000);
[Benchmark(Description = "IEnumerable.Any()")]
public bool EnumerableAny() => _enumerable.Any(x => x > 5000);
public static void RunBenchmarks()
{
var summary = BenchmarkRunner.Run<AnyVsExistsBenchmark>();
Console.WriteLine(summary);
}
}
测试内容:
在.NET 9中,基准测试显示在枚举集合(如Array和List)中Any()和Exists()的差异约为2.5倍 - 在小集合和大集合中;然而中等大小集合的性能在Any()和Exists()之间相当。
现在,让我们切换回.NET 8再次检查结果:
如我们所见,.NET 8的Any()在所有测试中都明显落后。
但关键是:对于10万元素以下的集合,你需要秒表才能察觉差异。
// 清晰意图 vs 过早优化
if (users.Any(u => u.IsAdmin)) {...} // 👍 推荐
if (users.Exists(u => u.IsAdmin)) {...} // 🤔 "为什么不用Any?"
-- 都转为
IF EXISTS(SELECT 1 FROM Users WHERE IsAdmin = 1)...
"最好的性能优化是不需要做的优化" ——每个上线日后的资深开发者
虽然Exists()在合成基准测试中仍保持微弱优势,但.NET 9已使这种差异对大多数应用失去实际意义。新的选择标准应倾向于:
所以下次当你纠结Exists()与Any()时,请记住:在.NET 9中,你的时间更应该投入实际业务逻辑优化,而非方法调用的选择。