【发布时间】:2012-01-29 15:18:03
【问题描述】:
我正在做一些性能测试,并注意到像 LINQ 表达式
result = list.First(f => f.Id == i).Property
比
慢result = list.Where(f => f.Id == i).First().Property
这似乎违反直觉。我原以为第一个表达式会更快,因为它可以在满足谓词后立即停止遍历列表,而我原以为 .Where() 表达式可能会在调用 .First() 之前遍历整个列表结果子集。即使后者确实短路,它也不应该比直接使用 First 更快,但确实如此。
下面是两个非常简单的单元测试来说明这一点。在 TestWhereAndFirst 上进行优化编译时,在 .Net 和 Silverlight 4 上比 TestFirstOnly 快大约 30%。我尝试让谓词返回更多结果,但性能差异是相同的。
谁能解释为什么.First(fn) 比.Where(fn).First() 慢?与.Where(fn).Count() 相比,我看到.Count(fn) 的类似反直觉结果。
private const int Range = 50000;
private class Simple
{
public int Id { get; set; }
public int Value { get; set; }
}
[TestMethod()]
public void TestFirstOnly()
{
List<Simple> list = new List<Simple>(Range);
for (int i = Range - 1; i >= 0; --i)
{
list.Add(new Simple { Id = i, Value = 10 });
}
int result = 0;
for (int i = 0; i < Range; ++i)
{
result += list.First(f => f.Id == i).Value;
}
Assert.IsTrue(result > 0);
}
[TestMethod()]
public void TestWhereAndFirst()
{
List<Simple> list = new List<Simple>(Range);
for (int i = Range - 1; i >= 0; --i)
{
list.Add(new Simple { Id = i, Value = 10 });
}
int result = 0;
for (int i = 0; i < Range; ++i)
{
result += list.Where(f => f.Id == i).First().Value;
}
Assert.IsTrue(result > 0);
}
【问题讨论】:
-
您最初的想法是错误的:LINQ 执行惰性计算,因此当调用
First()时,它只会查询(返回值)Where(...)的一个匹配项,而不会再要求另一个匹配项。因此,将检查与调用First(...)时完全相同数量的元素(即直接使用谓词)。 -
我得到相同的结果,
.Where().First()是 0.021 秒,.First()是 0.037 秒。这是一个简单的ints 列表。 -
根据我的测试,它还取决于您要查找的元素。只需在应用 Where 和第一个谓词时尝试使用特定的 i 值。我尝试使用值 1 和更高版本的 4999。我看到了结果的差异。似乎 First 循环遍历每个项目并匹配特定谓词,直到匹配为止。
-
@minitech 你没有在秒表上打电话给
Reset();您的测试实际上表明First()明显更快。
标签: c# .net performance linq