为什么在添加10000000个整数时,在ArrayList和List中分配时间是一样的?

时间:2018-02-10 14:09:08

标签: c# list arraylist collections types

我有以下代码,我通过添加10000000整数来比较ArrayList和List的性能。在ArrayList中我有装箱和拆箱,所以在第一个循环中,添加整数的时间远远大于List,但是assignig的时间稍后整数到元素的形式列表和arrayList是相似的,即使在arrayLIst我必须做拆箱。为什么?是因为ArrayList中的整数装箱和拆箱发生在第二个循环之前?

int numbers = 10000000;
ArrayList integerArrayList = new ArrayList();
Stopwatch timer = new Stopwatch();
timer.Start();

for (int i = 0; i < numbers; i++)
{
    integerArrayList.Add(i); //niejawna konwersja na object
}
timer.Stop();
var timeTestingIntegerArrayList = timer.ElapsedMilliseconds;
Console.WriteLine($"The time for adding {numbers} numbers to Arraylist is: {timeTestingIntegerArrayList} ms");
timer.Reset();

timer.Start();

for (int i = 0; i < numbers; i++)
{

    int number = (int)integerArrayList[i]; //unboxing
}
timer.Stop();
var arrayListWriteTime = timer.ElapsedMilliseconds;
Console.WriteLine($"The time for writting {numbers} numbers from Arraylist is: {arrayListWriteTime} ms");
timer.Reset();

Console.WriteLine($"The whole time for adding and writting {numbers} numbers from Arraylist is: {arrayListWriteTime + timeTestingIntegerArrayList} ms");` 

int numbers = 10000000;

List<int> integerList = new List<int>();
Stopwatch timer = new Stopwatch();

timer.Start();
for (int i = 0; i < numbers; i++)
{
    integerList.Add(i);
}
timer.Stop();   
var timeTestingIntegerList = timer.ElapsedMilliseconds;
Console.WriteLine($"The time for adding {numbers} numbers to list is: {timeTestingIntegerList} ms");
timer.Reset();

timer.Start();
for (var i = 0; i < numbers; i++)
{

    int number = integerList[i];

}
timer.Stop();
var listWriteTime = timer.ElapsedMilliseconds;
Console.WriteLine($"The time for assigning {numbers} numbers from list is: {listWriteTime} ms");
timer.Reset();


Console.WriteLine($"The whole time for adding and writting the integer numbers is: {timeTestingIntegerList + listWriteTime}");

2 个答案:

答案 0 :(得分:3)

您的程序生成类似的输出

The time for adding 10000000 numbers to Arraylist is: 1824 ms
The time for writting 10000000 numbers from Arraylist is: 100 ms
The whole time for adding and writting 10000000 numbers from Arraylist is: 1924 ms
The time for adding 10000000 numbers to list is: 111 ms
The time for assigning 10000000 numbers from list is: 77 ms
The whole time for adding and writting the integer numbers is: 188
  

但是指定的时间以后整数到元素的形式   list和arrayList是相似的,即使在arrayLIst中我也必须这样做   开箱

不,列表分配比arraylist赋值快。如果比较IL生成的代码,ArrayList和List赋值之间的差异几乎只是一条指令。

ArrayList

L_0083: ldloc.s num8
    L_0085: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
    L_008a: unbox.any int32
    L_008f: stloc.s num9
    L_0091: nop 
    L_0092: ldloc.s num8
    L_0094: stloc.s num7
    L_0096: ldloc.s num7
    L_0098: ldc.i4.1 
    L_0099: add 
    L_009a: stloc.s num8
    L_009c: ldloc.s num8
    L_009e: ldloc.0 

<强>列表

L_017d: callvirt instance !0 [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
L_0182: stloc.s num12
L_0184: nop 
L_0185: ldloc.s num11
L_0187: stloc.s num7
L_0189: ldloc.s num7
L_018b: ldc.i4.1 
L_018c: add 
L_018d: stloc.s num11
L_018f: ldloc.s num11
L_0191: ldloc.0 

L_008a:unbox.any int32 是数组列表中唯一出现的单条指令,因此与普通列表相比,Array List中有一些额外的时钟节拍。 因此,正如预期的那样,由于unbox,arraylist与list相比有点慢,但是与装箱相比,拆箱更快。

  

是否因为ArrayList中的整数装箱和拆箱发生在第二次循环之前?

!!。两个循环彼此独立,没有共享变量或实例将导致您的假设。

答案 1 :(得分:2)

StopWatch类绝对是快速和脏分析某些代码的不错选择。当两个不同部分之间存在较大差异时,您可以使用它,或者大致了解两个代码如何相互比较。但是,如果要获得真正准确的比较,则需要使用实际的基准设置。主要区别在于基准程序将连续多次执行测试,而不是手动执行几次。然后,它会将结果平均在一起,以消除在个别运行期间出于各种原因发生的噪音。

.NET中的一个常见选择是使用BenchmarkDotNet。这是我在设置基准测试时使用的那个,你可以找到我的完整代码here。希望在设置这个时,我没有做出明显的错误。 :)

方法

那就是说,我的方法很简单。我创建了三个不同的集合。 int[]ArrayListList<int>。我添加了int[]作为所有比较的基线,因为它理论上应该是最快的。

然后我针对每个基准运行了两组基准测试:从所有三个集合中检索第一个项目,并检索集合的所有项目。我添加了单个检索以尝试大致了解拆箱所需的时间。

结果

您可以查看我的结果here

  

摘要

     

LoopOverArrayList:27,418,009.3179 ns

     

LoopOverList:6,741,538.0712 ns

     

SingleArrayListAccess:2.5473 ns

     

SingleListAccess:1.2240 ns

从结果中我们可以看到,取消装箱确实比从List<T>直接访问需要更多时间。但是,它也不是很慢。因此,您的结果很可能只是来自某些噪音,这些噪音与您的个别跑步混合在一起,通过基准测试中的多次运行得到平滑。我鼓励你自己执行上面的基准测试,看看你是否得到了类似的结果。很可能它们会落在类似的范围内。

所以,是的,每次ArrayList次访问都会发生取消装箱,而且它确实会加起来但不是很大。