有没有一个好的资源可以概述linq优化?

9
Linq做了很多聪明的事情,例如使用IList上的Count()方法返回Count属性的结果。有没有一个好的来源可以概述这些优化呢?
这将非常有趣,因为在我知道上述内容之前,我从未使用过Count(),因此通常返回一个List<T>而不是仅返回IEnumerable<T>,因为我知道调用者经常需要列表实例的计数。
但是,考虑到Count()实际上并不计算包含在IEnumerable<T>中的实例,而是返回返回的List的Count属性的结果,因此不会损失性能,我改变了很多从List返回到IEnumerable<T>的类型。

“Linq做了很多优化,例如使用IList上的Count()方法返回Count-property的结果。” 这句话的意思是什么? - Mitch Wheat
@Mitch:可以假设LINQ查询在只需要简单的Count()调用时,并不会检索所有底层数据。 - Pontus Gagge
我刚刚学到,对列表调用AsEnumerable方法不会创建新实例,而只是返回现有实例。但也许优化这个词并不准确。我已经更改了问题文本,以更精确地表达我的意思。 - HCL
我不同意你的观点,这些是启发式算法,与优化有很大关系。 - John Leidegren
你能否将“linq cleverness”重新表述成一个问题吗?例如:“是否有一个好的来源可以概述linq优化?” - tobsen
2个回答

13

尝试使用.NET Reflector,它是一个浏览类库的好工具,具有强大的反编译功能,可以让您查看与源代码几乎相同的内容。

例如,Count() 扩展方法的实现如下:

if (source == null)
{
    throw Error.ArgumentNull("source");
}
ICollection<TSource> is2 = source as ICollection<TSource>;
if (is2 != null)
{
    return is2.Count;
}
ICollection is3 = source as ICollection;
if (is3 != null)
{
    return is3.Count;
}
int num = 0;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        num++;
    }
}
return num;

如果源代码没有实现集合接口,您就必须进行计数以获得真正的计数。通过这种方式浏览代码是学习的好方法。


6

目前我所知道的优化:

  • Count 如果序列实现了ICollection<T>并且没有使用谓词,就会使用 Count 属性。(在 .NET 4 中,Count 在非泛型 ICollection 上也进行了优化。)

  • ElementAt/ElementAtOrDefault 如果序列实现了IList<T>,就会通过索引访问。

  • Last/LastOrDefault 如果序列实现了 IList<T> 并且没有使用谓词,就会通过索引访问。

  • ToArray/ToList 如果序列实现了ICollection<T>,则使用 Count 属性来更有效地分配内存。(但它们都没有针对 ICollection 进行优化。)

可能存在但尚未优化的优化:

  • Last/LastOrDefault在使用谓词时不进行优化。它们可以通过在IList<T>中向后迭代并通过索引访问每个元素来进行优化。

  • SequenceEqual 可以针对 ICollection<T>ICollection 进行优化,使用 Count 属性确定列表是否具有相同长度并尽早退出。

  • Skip 可以在IList<T>上进行优化,通过索引访问元素并直接从索引n开始而不是迭代和丢弃前面的n个元素。

  • ToArray/ToList也可以针对ICollection进行优化,使用Count属性更高效地分配内存。

  • ToDictionary 可以在ICollection<T>ICollection上进行优化,使用Count属性更高效地分配内存。


1
我在开发Nito.Linq库时,使用Reflector进行了深入研究。Luke的回答已经很完整了。我只想补充一点: ToListToArray确实使用Count来减少内存重新分配。 此外,通过使用CountEmptySequenceEqual也可能被优化。最后,Reverse也有潜力进行优化,但这是有争议的,因为它会改变语义(从缓冲到流式) 。 - Stephen Cleary
@Stephen:我完全忘记了SequenceEqual的可能优化,尽管我在自己的LINQ帮助库中有一个经过优化的版本。我会把它加到列表中。你能详细说明一下如何优化Empty吗?据我所知,它只返回一个单例空序列。 - LukeH
你是对的;我重新检查了我的笔记,“Empty”只是我错误中的注释。抱歉... - Stephen Cleary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接