[英]How does linq concat work under the hood?
我正在考慮替換如下代碼:
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)
是否有任何參考說明如何為注重性能的人實現linq api函數?
謝謝!
編輯
好的,沒有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
擴展方法時,您的代碼才能工作。 我建議您不要這樣做-出於我同意的原因,請參閱Eric Lippert的博客文章 。
我建議您將其寫為:
foreach (var meshCut in meshCuts0.Concat(meshCuts1))
{
ComputePolygons(meshCut, polygons);
}
Concat
表現很好-只需在第一個序列上進行迭代,然后在第二個序列上進行迭代,就可以生成項目。 它不會緩沖所有元素。 對於所添加的額外間接級別,性能會受到很小的影響,僅此而已。
我希望Mono的行為方式相同Concat
非常簡單。 實際上,由於Mono是開源的,因此您可以自己檢查它 。 (當然,它可能會隨着時間推移而移動...)
不久前,我在博客中詳細介紹了LINQ to Objects,從頭開始重新實現了整個過程,並記錄了其性能的各個方面,包括需要改進的地方。 有關更多詳細信息,請參閱我的Edulinq博客系列 。
這就是linq concat在后台運行的方式。
Microsoft .net Framework 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;
}
Mono(來源: 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 decompiler的免費工具。 您可以加載每個程序集,甚至可以將標准程序集進行反編譯並獲取源代碼。 如果查看程序集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上找到源。 可在此處建立Enumerable類: link 。 以及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; }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.