我主要理解延迟执行,但我对某个特定情况有疑问:
给出代码片段,例如
var resultsOfInterest = from r in ...
select r;
foreach (var x in resultsOfInterest)
{
//do something with x
}
查询 resultsOfInterest 执行了多少次?一旦设置foreach循环,或每个元素'x'一次?
会更有效率吗? foreach (var x in resultsOfInterest.ToArray())
{
//do something with x
}
TIA
答案 0 :(得分:5)
它将在循环之前执行一次,当GetEnumerator()
方法将在查询变量上执行时。以下是 foreach 循环的样子:
var enumerator = resultsOfInterest.GetEnumerator(); // query executed here
while(enumerator.MoveNext()) // iterating over results of query execution
{
var x = enumerator.Current;
// do something with x
}
第二个样本效率不高,它只是将查询执行结果存储在数组中,然后调用数组迭代器:
var enumerator = resultsOfInterest.ToArray().GetEnumerator();
// loop stays same
答案 1 :(得分:3)
在这两种情况下,它只运行一次。
在第一个示例中,(如果这是Linq-to-Objects查询),它运行的时间足够长,以便在每次迭代时获得下一个x
。在第二个示例中,它必须立即评估整个结果集并将其存储到数组中。
因此,假设这是一个昂贵的查询,每个项目需要1秒钟,列表中有20个项目,两个查询都需要大约20秒来处理所有项目。但是,第一个将在每次迭代时被阻塞1秒而它获得下一个项目,但第二个将在循环开始之前被阻塞20秒,然后相当快地遍历数组中的所有项目。 / p>
在实际评估查询时,它们的效率都不高。但是,一般情况下,您应该避免对ToArray
或ToList
进行不必要的调用,因为除了评估查询之外,还必须为结果分配一个数组(List<T>
将其项存储在内部数组)。对于20个项目的列表,这并不意味着什么,但是当你有几千个项目时,这可能会导致一些明显的减速。当然,这并不意味着ToArray
总是坏。如果在前面的示例中有5个foreach
- 循环,则将结果存储在数组中并循环遍历数组而不是每次重新评估查询实际上会使代码加速大约80秒
答案 2 :(得分:0)
在这两种情况下,查询只执行一次,但在第二种情况下,有两个枚举。
假设1000件物品:
案例1:
select
子句,将结果分配给x
。案例2:
select
子句,将结果分配给数组。x
。因此通常不需要创建数组。但是如果你需要自己多次枚举相同的项目,并且数组访问速度比select
快,那么创建数组会更有效。