各种列表初始化和填充技术的性能差异

Mau*_*tro 5 c# performance list

我试图找出在构造函数中设置列表的容量是否可以使使用List<T>(IEnumerable<T>)vs List<T>()+之间已经可以忽略不计的性能差异变平AddRange(IEnumerable<T>)

我发现设置的能力之前,AddRange()实际上导致大致相同的性能与初始集合构建的名单。

但还有更多。如果你使用Add()而不是AddRange()?出于某种原因,性能似乎提高了 32%

那么如果我在Add()不使用初始容量初始化列表的构造函数的情况下使用呢?看起来性能比之前的 Add() 方法差,但仍然比AddRange()方法好:性能提升了 26%。

这很奇怪,让我怀疑我的测试是否有效;所以我发布了我所做的测试(在没有调试器的情况下以发布模式运行)。

有人可以证实这一点吗?

int items = 100000;
int cycles = 10000;

var collectionToCopy = Enumerable.Range( 0, items );

var sw0 = new Stopwatch();
sw0.Start();
for( int i = 0; i < cycles; i++ )
{
    List<int> list = new List<int>( collectionToCopy );
}
sw0.Stop();
Console.WriteLine( sw0.ElapsedMilliseconds );

var sw1 = new Stopwatch();
sw1.Start();
for( int i = 0; i < cycles; i++ )
{
    List<int> list = new List<int>( items );
    list.AddRange( collectionToCopy );
}
sw1.Stop();
Console.WriteLine( sw1.ElapsedMilliseconds );

var sw4 = new Stopwatch();
sw4.Start();
for( int i = 0; i < cycles; i++ )
{
    List<int> list = new List<int>();
    list.AddRange( collectionToCopy );
}
sw4.Stop();
Console.WriteLine( sw4.ElapsedMilliseconds );

var sw2 = new Stopwatch();
sw2.Start();
for( int i = 0; i < cycles; i++ )
{
    List<int> list = new List<int>( items );
    foreach( var item in collectionToCopy )
        list.Add( item );
}
sw2.Stop();
Console.WriteLine( sw2.ElapsedMilliseconds );

var sw3 = new Stopwatch();
sw3.Start();
for( int i = 0; i < cycles; i++ )
{
    List<int> list = new List<int>();
    foreach( var item in collectionToCopy )
        list.Add( item );
}
sw3.Stop();
Console.WriteLine( sw3.ElapsedMilliseconds );
Run Code Online (Sandbox Code Playgroud)

结果:

13400 - 用集合初始化的构造函数

13423 - 用容量 + AddRange(collection) 初始化的构造函数

14857 - 无参数构造函数 + AddRange(集合)

9003 - 构造函数初始化为容量 + 添加(项目)

9841 - 无参数构造函数 + Add(item)

Xia*_* Ge 4

恶魔就在Enumerable.Range(0, items)。将其更改为Enumerable.Range(0, items).ToList();将为您带来预期的结果。

AddRange(IEnumerable collectionToCopy)将检查输入的实际类型。如果输入是连续的(例如列表、数组……),它将尝试复制。否则,它会退回到枚举和简单的 Add()。

这是后备代码

using(IEnumerator<T> en = collection.GetEnumerator()) {
   while(en.MoveNext()) {
        Insert(index++, en.Current);                                    
Run Code Online (Sandbox Code Playgroud)

在后备情况下,List.AddRange 给出的较差性能可能来自 IEnumertor 开销