我有以下代码,我通过添加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}");
答案 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[]
,ArrayList
和List<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
次访问都会发生取消装箱,而且它确实会加起来但不是很大。