为什么一个简单的List <t>似乎比ArrayList慢?</t>

时间:2012-03-05 08:33:45

标签: c# .net generics arraylist clr

出于好奇,我想测试将GenericList与ArrayList进行比较的刻度数。

对于下面的代码,当我检查秒表时,ArrayList似乎更快。

我做错了还是有解释? (我相信List会更快)

测试代码和下面的输出

private static void ArrayListVsGenericList()
{
    // Measure for ArrayList
    Stopwatch w0 = new Stopwatch();
    w0.Start();

    ArrayList aList = new ArrayList();

    for (int i = 0; i < 1001; i++)
    {
        Point p = new Point();
        p.X = p.Y = i;

        aList.Add(p);
    }

    foreach (Point point in aList)
    {
        int v0 = ((Point) aList[8]).X; //unboxing
    }


    w0.Stop();

    // Measure for Generic List<Point>
    Stopwatch w1 = new Stopwatch();
    w1.Start();

    List<Point> list = new List<Point>();

    for (int i = 0; i < 1001; i++)
    {
        Point p = new Point();
        p.X = p.Y = i;

        list.Add(p); 
    }


    foreach (var point in list)
    {
        int v1 = list[8].X;
    }

    w1.Stop();

    Console.WriteLine("Watch 0 : " + w0.ElapsedTicks);
    Console.WriteLine("Watch 1 : " + w1.ElapsedTicks);
    Console.WriteLine("Watch 0 > Watch 1 : " + (w0.ElapsedTicks > w1.ElapsedTicks));
}

enter image description here

2 个答案:

答案 0 :(得分:7)

更改测试程序以至少运行两次方法并忽略第一次运行。结果是由具体类型List<Point>的代码生成和jitting引起的。

在我的机器上,这会产生以下输出:

  Watch 0 : 154
  Watch 1 : 74
  Watch 0 > Watch 1 : True

这几乎是人们所期望的。

答案 1 :(得分:5)

你没有消除像JIT这样的第一个执行效果。泛型需要为每个值类型参数编译一次。

ArrayList已经预编译了ngen。

List<T>仅针对某些参数类型进行了预编译(我读过核心库实例化了一些常见参数的最重要的泛型,如object,bool,int,...),如果有的话。因此会产生一次性费用。

您还应该注意,ArrayList的大部分性能成本都是间接的:拳击给GC带来了更大的压力,并且使用了更多的内存。但是你的测试不会衡量。产生更多垃圾的成本还取决于存在多少其他对象以及对象的生命周期。

当你编写测试时,你应该在实际测试之前执行一次所有代码,或者使用那么多迭代,一次成本可以忽略不计。使用发布版本并运行而不连接调试器也很重要。