【发布时间】:2014-10-28 08:05:44
【问题描述】:
我创建了一个函数来递归查找符合条件的第一个或默认项(第一个代码块)。
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,在12核机器上发布,windows 7,Framework.Net 4.5,
我的结论:
在我的情况下,它在非 linq 版本中要快约 3 倍。 LINQ 的可读性更好,但谁在乎它何时在一个库中,您应该只记住它的作用以及如何调用它(在这种情况下 - 不是一般的绝对情况)。 LINQ 几乎总是比好的编码方法慢。 我会个人口味:
- LINQ:性能不是真正的问题(大多数情况下) 具体项目代码
- Non Linq:性能是特定项目代码中的问题,在库中使用的位置以及代码应该稳定和固定的位置,方法的使用应该有详细的文档,我们 不应该真的需要在里面挖。
【问题讨论】:
-
底层编译器编译的 linq 代码与 foreach 代码截然不同,这就是你的区别所在。
-
您不需要重置计时器以获得第二次测试迭代的正确计数吗?
-
@entropic,谢谢... :-( !!!!!
-
与其尝试将一大堆操作混合在一起,不如保持关注点分离。创建一个遍历基于树的结构并将其展平的方法,您已经有一种方法可以将序列过滤为符合条件的项目,并且您已经有一种方法可以获取序列中的第一项或默认值。然后,如果您真的需要,您可以组合这三个操作,尽管一旦您构建了每个构建块,它并不会完全添加很多。
标签: c# performance linq memory optimization