时间:就刚才。
地点:我寝室。
人物:我。
最近我好像跟“性能”、“效率”这些敏感词汇较上劲了,先汗一个。
因为某些奇异的原因,我又做了如下极端无聊的事情,那就是对List<T>与ArrayList的“性能”的一个小测试。
在这个测试中,重点在于对List<T>与ArrayList的[Add,遍历]性能作讨论,坚决不将话题牵扯到普通容器和泛型容器。
测试中用到了老赵的一个简单的性能计数器——CodeTimer。
由于值类型存在boxing/unboxing,泛型容器有得天独厚的优势,二者几乎不存在可比性,所以我没做值类型的测试。
最终测试结果都包含Debug/Release两个数值。
经过
这里我用的元素类型是我自己定义的一个类,其定义如下
}
用于测试的容器有两个:System.Collections.ArrayList,以及System.Collections.Generic.List<Class>
容器定义为
首先是测试Add的性能
测试代码是:
list.Add(obj);
});
插入测试结果:
可以看出List<Class>比ArrayList插入快一些。
下面就是大家比较关注的遍历性能测试了。
这里有两种遍历,一种是for,一种是foreach。容器内的东西就是刚才插入的那一堆。
下面是测试代码:
}
});
呃……然后是遍历的结果
这个结果有点出乎我意料,在Debug模式下,ArrayList和List<Class>几乎平手,差别在2%左右,foreach上ArrayList则完全败北。在Release模式下却发生了很大的变化:for方面List<Class>拥有非常惊人的优化幅度,ArrayList的for虽然也快了很多但是依然不及List<Class>;foreach方面ArrayList停滞不前,而List<Class>却进一步拉大差距。
考虑到有时候我们会这么做
}
});
这是我们的老师常常教我们的一种方法。结果如下:
在Debug模式下,ArrayList终于“雪耻”,以大约1.3%的微弱优势超过了List<Class>,但很可惜,到了Release下List<Class>没有给ArrayList留下任何的机会。
结果
在这个测试所能涵盖的范围内,我们找不到任何理由为ArrayList树立功德碑,List<Class>以压倒性的优势告诉我们选择它是正确的。
后话
对于值类型,泛型容器的效率是有目共睹的,我不想做那种比这个无聊的测试还无聊的无聊测试了。
对于这个测试中的for测试,对ArrayList是不公平的,因为那一句var tempObj = arrayList[i];编译器显然会把var编译成object,而我们期待的是Class,实际应用中这里势必要发生type casting,所以ArrayList的for在实际中效率负担还会多上那么一丁丁点。
对于这个测试中的foreach测试,对ArrayList还是不公平的,因为我们foreach的是(Class it),对于ArrayList内部的IEnumerable实现来说,我们从这个代码中很难说ArrayList做了怎样的type casting,而对于List<Class>来说这个type casting我们是知道,它显然是不用做的。
但是话说回来,ArrayList的type casting不就是我们讨厌的地方吗?那么还有什么理由不选择List<T>?