Arm*_*ots 7 c# linq collections performance
有兴趣,方法有什么不同.
所以,我创建了两个片段.
Snippet A
List<int> a = new List<int>();
a.Add(4);
a.Add(6);
int b = a.First();
Run Code Online (Sandbox Code Playgroud)
和
Snippet B
List<int> a = new List<int>();
a.Add(4);
a.Add(6);
int b = a[0];
Run Code Online (Sandbox Code Playgroud)
在IL,我们相信,所以
Snippet A IL
IL_0000: nop
IL_0001: newobj System.Collections.Generic.List<System.Int32>..ctor
IL_0006: stloc.0 // a
IL_0007: ldloc.0 // a
IL_0008: ldc.i4.4
IL_0009: callvirt System.Collections.Generic.List<System.Int32>.Add
IL_000E: nop
IL_000F: ldloc.0 // a
IL_0010: ldc.i4.6
IL_0011: callvirt System.Collections.Generic.List<System.Int32>.Add
IL_0016: nop
IL_0017: ldloc.0 // a
IL_0018: call System.Linq.Enumerable.First
IL_001D: stloc.1 // b
IL_001E: ret
Run Code Online (Sandbox Code Playgroud)
和
Snippet B IL
IL_0000: nop
IL_0001: newobj System.Collections.Generic.List<System.Int32>..ctor
IL_0006: stloc.0 // a
IL_0007: ldloc.0 // a
IL_0008: ldc.i4.4
IL_0009: callvirt System.Collections.Generic.List<System.Int32>.Add
IL_000E: nop
IL_000F: ldloc.0 // a
IL_0010: ldc.i4.6
IL_0011: callvirt System.Collections.Generic.List<System.Int32>.Add
IL_0016: nop
IL_0017: ldloc.0 // a
IL_0018: ldc.i4.0
IL_0019: callvirt System.Collections.Generic.List<System.Int32>.get_Item
IL_001E: stloc.1 // b
IL_001F: ret
Run Code Online (Sandbox Code Playgroud)
Snippet B产生了一个更多的IL命令,但最终接近哪个更快?
你可以自己检查一下:
static void Main()
{
List<long> resultsFirst = new List<long>();
List<long> resultsIndex = new List<long>();
Stopwatch s = new Stopwatch();
for (int z = 0; z < 100; z++)
{
List<int>[] lists = new List<int>[10000];
int temp = 0;
for (int i = 0; i < lists.Length; i++)
lists[i] = new List<int>() { 4, 6 };
s.Restart();
for (int i = 0; i < lists.Length; i++)
temp = lists[i].First();
s.Stop();
resultsFirst.Add(s.ElapsedTicks);
s.Restart();
for (int i = 0; i < lists.Length; i++)
temp = lists[i][0];
s.Stop();
resultsIndex.Add(s.ElapsedTicks);
}
Console.WriteLine("LINQ First() : " + resultsFirst.Average());
Console.WriteLine(Environment.NewLine);
Console.WriteLine("By index : " + resultsIndex.Average());
Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)
发布模式下的输出:
LINQ First():367
按指数:84
调试模式下的输出:
LINQ First():401
按索引:177
PS
方法First的源代码是:
public static TSource First<TSource>(this IEnumerable<TSource> source)
{
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
if (list.Count > 0)
{
return list[0];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
return enumerator.Current;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
转换操作source as IList<TSource>或创建Enumerator对象很可能是因为First()它相当慢的原因.
该Enumerable.First方法定义为
public static TSource First<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw Error.ArgumentNull("source");
IList<TSource> list = source as IList<TSource>;
if (list != null) {
if (list.Count > 0) return list[0];
}
else {
using (IEnumerator<TSource> e = source.GetEnumerator()) {
if (e.MoveNext()) return e.Current;
}
}
throw Error.NoElements();
}
Run Code Online (Sandbox Code Playgroud)
因此,对于 aList<T>它最终在空检查和强制转换后使用索引器。看起来不多,但是当我测试性能时,First它比索引器慢 10 倍(for循环,10 000 000 次迭代,发布版本:第一个 - 100 毫秒,索引器 - 10 毫秒)。
| 归档时间: |
|
| 查看次数: |
2848 次 |
| 最近记录: |