C# 跳过并接收Linq对象的性能
搜索“跳过”和“接受”功能的替代功能 链接的1表示“每次调用Skip()时,它都必须从头开始迭代您的集合,以跳过所需的元素数,从而在循环中产生循环(n2行为)” 结论:对于大量收集,不要使用Skip and Take。找到另一种方法来迭代并划分集合C# 跳过并接收Linq对象的性能,c#,performance,linq,paging,C#,Performance,Linq,Paging,搜索“跳过”和“接受”功能的替代功能 链接的1表示“每次调用Skip()时,它都必须从头开始迭代您的集合,以跳过所需的元素数,从而在循环中产生循环(n2行为)” 结论:对于大量收集,不要使用Skip and Take。找到另一种方法来迭代并划分集合 为了在一个庞大的集合中访问最后一页数据,您能给我们建议一种除了“跳过”和“采取”方法之外的方法吗 取决于您的实现,但是使用索引数组来代替是有意义的。查看forSkip,您可以看到它枚举了所有项,甚至是要跳过的前n项。 但这很奇怪,因为有几种LINQ方
为了在一个庞大的集合中访问最后一页数据,您能给我们建议一种除了“跳过”和“采取”方法之外的方法吗 取决于您的实现,但是使用索引数组来代替是有意义的。查看for
Skip
,您可以看到它枚举了所有项,甚至是要跳过的前n项。但这很奇怪,因为有几种LINQ方法对集合进行了优化,比如
Count
和Last
Skip
显然没有
如果您有一个数组或IList
,则可以使用索引器真正跳过它们:
for (int i = skipStartIndex; i < list.Count; i++) {
yield return list[i];
}
for(int i=skipStartIndex;i
在内部,它确实是正确的:
private static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (count > 0 && enumerator.MoveNext())
--count;
if (count <= 0)
{
while (enumerator.MoveNext())
yield return enumerator.Current;
}
}
}
private静态IEnumerable SkipIterator(IEnumerable源代码,int计数)
{
使用(IEnumerator enumerator=source.GetEnumerator())
{
while(计数>0&&enumerator.MoveNext())
--计数;
如果(计数迭代部分可能只适用于IEnumerable
,如果IList
没有使用索引,我会感到惊讶。@AlexanderDerck不幸的是没有-最近在corefx repo中实现了此优化。Jon Skeet谈到了优化Edulink系列和再次在第40部分:。我的观点是,他不一定认为这是一个好主意。也许。在第23节中,他对这个主题发表了各种各样的胡言乱语,但在第40节中,他似乎认为这不是一个好主意。@JasonBoyd,正如usr所说,corefx实际上已经进行了优化。对可观察到的变化进行了评估,但认为可以接受able.See取决于版本。当前已针对列表、OrderBy
的结果和其他几种情况进行了优化,希望很快会有更多改进。请注意,Skip()的当前行为
在一个IList上
与您这里的功能非常接近。使用skip获取最后一页数据的效率很低。从20万条记录中提取最后100条记录需要花费近13秒。查看有价值的评论,我是否可以得出结论,我们不应该使用skip和Take获取大量数据。不,我们没有使用数组和列表.我们使用了延迟查询(IEnumerable)从数据库中获取数据。
public static class IReadOnlyListExtensions
{
public static IEnumerable<T> Skip<T>(this IReadOnlyList<T> collection, int count)
{
if (collection == null)
return null;
return ICollectionExtensions.YieldSkip(collection, count);
}
private static IEnumerable<T> YieldSkip<T>(IReadOnlyList<T> collection, int count)
{
for (int index = count; index < collection.Count; index++)
{
yield return collection[index];
}
}
}
if (collection is IReadOnlyList<T>)
{
// do optimized skip
}