我发现有时如果使用 .ToArray()
强制立即执行 LINQ to Objects 查询,其性能可以显着提高,但不太明白为什么。例如,在下面的示例中,函数 Deferred()
的执行速度比函数 Immediate()
慢得多,并且随着 的值呈指数增长limit
(也许这两个函数都是指数级的,但是 Immediate()
的执行时间太短了,我无法明确地说)。
public void Deferred()
{
var all = Range(limit);
var even = from e in EvenRange(limit) where all.Contains(e) select e;
var odd = from o in OddRange(limit) where !even.Contains(o) select o;
var query = from q in odd select q;
foreach(var i in query) { var j = i+1; }
}
public void Immediate()
{
var all = Range(limit);
var even = (from e in EvenRange(limit) where all.Contains(e) select e)
.ToArray();
var odd = (from o in OddRange(limit) where !even.Contains(o) select o)
.ToArray();
var query = (from q in odd select q).ToArray();
foreach(var i in query) { var j = i+1; }
}
public static IEnumerable<int> OddRange(int stop)
{
for (int i = 1; i < stop; i+=2) yield return i;
}
public static IEnumerable<int> EvenRange(int stop)
{
for (int i = 2; i < stop; i+=2) yield return i;
}
public static IEnumerable<int> Range(int stop)
{
for (int i = 0; i < stop; ++i) yield return i;
}
是什么导致了这种减速?这只是编译器生成的额外代码,并且每次访问可枚举时都必须运行,还是 Deferred()
也会进入一些额外的循环,从而改变查询的“Big O”复杂性?
最佳答案
据我所知 IEnumerable 不会缓存结果,因此涉及 Even.Contains 的子句(必须检查 Even 的所有元素)强制完全重新枚举 Even,从而显示您注意到的性能行为。在数组或列表中转换偶数应该会在枚举奇数时显示出良好的性能。其他 .NET 语言(例如 F#)包含缓存枚举结果的方法(如果您感兴趣,可以查看 F# 的 Seq.cache 方法)
关于.net - LINQ 性能 - 延迟执行与立即执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/872697/