我写了一个函数来递归查找符合条件的第一个或默认项(第一个代码块)。
Resharper建议我将几行代码更改为仅一个LINQ行(第二个代码块)。
我想知道Resharper的建议是否会给我相同的性能和相同的内存占用。我进行了性能测试(第三个代码块)。结果正是我所期望的。为什么差异如此之大?
8156 milliseconds
Laure
23567 milliseconds
Laure LINQ
这种差异是从哪里来的?为什么结果不同?或者至少更接近?
public static T RecursiveFirstOrDefault<T>(this T item, Func<T, IEnumerable<T>> childrenSelector, Predicate<T> condition)
where T : class // Hierarchy implies class. Don't need to play with "default()" here.
{
if (item == null)
{
return null;
}
if (condition(item))
{
return item;
}
foreach (T child in childrenSelector(item))
{
T result = child.RecursiveFirstOrDefault(childrenSelector, condition);
if (result != null)
{
return result;
}
}
return null;
}
但是Resharper建议我将foreach块转换为以下LINQ查询:
public static T RecursiveFirstOrDefaultLinq<T>(this T item, Func<T, IEnumerable<T>> childrenSelector, Predicate<T> condition)
where T : class // Hierarchy implies class. Don't need to play with "default()" here.
{
if (item == null)
{
return null;
}
if (condition(item))
{
return item;
}
// Resharper change:
return childrenSelector(item).Select(child => child.RecursiveFirstOrDefaultLinq(childrenSelector, condition)).FirstOrDefault(result => result != null);
}
测试:
private void ButtonTest_OnClick(object sender, RoutedEventArgs e)
{
VariationSet varSetResult;
Stopwatch watch = new Stopwatch();
varSetResult = null;
watch.Start();
for(int n = 0; n < 10000000; n++)
{
varSetResult = Model.VariationRef.VariationSet.RecursiveFirstOrDefault((varSet) => varSet.VariationSets,
(varSet) => varSet.Name.Contains("Laure"));
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds.ToString() + " milliseconds");
Console.WriteLine(varSetResult.Name);
watch.Reset();
varSetResult = null;
watch.Start();
for(int n = 0; n < 10000000; n++)
{
varSetResult = Model.VariationRef.VariationSet.RecursiveFirstOrDefaultLinq((varSet) => varSet.VariationSets,
(varSet) => varSet.Name.Contains("Laure"));
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds.ToString() + " milliseconds");
Console.WriteLine(varSetResult.Name + " LINQ");
}
我今天要走了……希望能够适当地回答有关测试的问题:x86,Release模式在12核机器上,Windows 7,.Net Framework 4.5。
我的结论:
在我的情况下,非LINQ版本大约快3倍。虽然使用LINQ更易读,但是在库中,你只需要记住它做了什么以及如何调用它(在这种情况下,不是绝对通用的情况),所以谁关心可读性呢?LINQ几乎总比良好编码的方法慢。 我个人的喜好:
- LINQ:在特定项目代码中性能并不是真正的问题时(大多数情况下)
- 非LINQ:在特定项目代码中性能是一个问题时,或者在库中使用时,在使用该方法时应该有稳定的、固定的代码,并且其使用方法应该得到充分的文档说明,我们不应该真正需要深入其中。
"abcd".FirstOrDefault(f => f > 'b')
返回'c'。 - user2023861