linq concat是如何在引擎盖下工作的
本文关键字:工作 引擎 concat linq | 更新日期: 2023-09-27 18:22:24
我正在考虑替换如下代码:
foreach (var meshCut in meshCuts0)
{
ComputePolygons(meshCut, polygons);
}
foreach (var meshCut in meshCuts1)
{
ComputePolygons(meshCut, polygons);
}
linq看起来像这样:
meshCuts0.Concat(meshCuts1).ForEach(m => ComputePolygons(m, polygons));
我不知道linq是如何实现的,所以我不确定性能后果。我很感激你的帮助。
1)
Concat会创建一个列表副本吗?还是只是一个枚举器在做这样的事情:
public static IEnumerable<T> Concat<T>(IEnumerable<T> a, IEnumerable<T> b)
{
foreach (var t in a)
{
yield return t;
}
foreach (var t in b)
{
yield return t;
}
}
2)
这会是Mono上的相同行为吗?
3)
有没有任何参考资料可以解释linqapi函数是如何为注重性能的人实现的?
谢谢!
编辑
好的,没有ForEach,所以假设我也定义了这样的东西:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach(T item in source)
action(item);
}
真正的问题是,仅仅为了精简代码,Concat是否会是一个昂贵的开销——多亏了这些评论,我现在明白了不是。
编辑2
啊,Jon Skeet建议不要添加ForEach。。。所以我不会!
http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx
首先,您的代码只有在同时在IEnumerable<T>
上引入ForEach
扩展方法的情况下才能工作。我建议你不要这么做——看看埃里克·利珀特的博客文章,原因我同意。
我建议你写为:
foreach (var meshCut in meshCuts0.Concat(meshCuts1))
{
ComputePolygons(meshCut, polygons);
}
Concat
执行得很好——它只是先迭代第一个序列,然后迭代第二个序列,在迭代过程中生成项。它不会缓冲所有元素。您添加的额外间接级别会对性能造成非常轻微的影响,但仅此而已。
我希望Mono也能有同样的表现——Concat
非常简单。事实上,由于Mono是开源的,您可以自己检查它。(当然,它可能会随着时间的推移而移动…)
不久前,我在博客中详细介绍了LINQ to Objects,从头开始重新实现了整个过程,并记录了其性能的各个方面,包括哪里还有改进的空间。查看我的Edulinq博客系列了解更多详细信息。
这就是linq-concat在后台的工作方式。
Microsoft.net框架4.0:
public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) {
if (first == null) throw Error.ArgumentNull("first");
if (second == null) throw Error.ArgumentNull("second");
return ConcatIterator<TSource>(first, second);
}
static IEnumerable<TSource> ConcatIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second) {
foreach (TSource element in first) yield return element;
foreach (TSource element in second) yield return element;
}
单声道(来源:https://github.com/mono/mono/blob/master/mcs/class/System.Core/System.Linq/Enumerable.cs#L584)
public static IEnumerable<TSource> Concat<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second)
{
Check.FirstAndSecond (first, second);
return CreateConcatIterator (first, second);
}
static IEnumerable<TSource> CreateConcatIterator<TSource> (IEnumerable<TSource> first, IEnumerable<TSource> second)
{
foreach (TSource element in first)
yield return element;
foreach (TSource element in second)
yield return element;
}
具体答案:
它没有创建任何副本,只是枚举。
是的。
对于注重性能的人来说,源代码是最好的。
-
它的工作原理就像你描述的一样。你可以下载一个很好的免费工具,名为JetBrains dotPeek-.net反编译器。您可以加载每个程序集,甚至是标准程序集来反编译并获取源代码。如果你查看汇编System.Core,命名空间System.Linq,类Enumerable,你可以看到:
public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) { if (first == null) throw Error.ArgumentNull("first"); if (second == null) throw Error.ArgumentNull("second"); return ConcatIterator<TSource>(first, second); } static IEnumerable<TSource> ConcatIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second) { foreach (TSource element in first) yield return element; foreach (TSource element in second) yield return element; }
谈到LINQ——它很懒,每个LINQ扩展方法都使用延迟计算。有一个好人Jon Skeet,他有一个博客。有许多文章名为"重新实现LINQ到对象:部分",所有这些文章都可以通过标签"LINQ"找到:链接
-
Mono是一个开源项目。你可以在github上找到来源。可枚举类可以在以下位置创建:链接。Concat的源代码:
public static IEnumerable<TSource> Concat<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second) { Check.FirstAndSecond (first, second); return CreateConcatIterator (first, second); } static IEnumerable<TSource> CreateConcatIterator<TSource> (IEnumerable<TSource> first, IEnumerable<TSource> second) { foreach (TSource element in first) yield return element; foreach (TSource element in second) yield return element; }