接上篇,发现一个神奇的现象,List<object>
的存储速度比List<T>
的速度要快
性能测试准备
既然要做性能测试,那我们肯定需要一个工具来统计代码块运行时间。C#里有现成的时间函数供我们使用,一般都是这么写:
1 | var time1 = System.DateTime.Now; |
有点儿麻烦,那我封装一下好了,成这样:
1 | class TimeCount |
直接调用Start和End就行
ArrayList
和List<object>
现在网上所有的说法都不赞同使用ArrayList
这个非泛型容器。理由是:
- 效率低下,涉及基本类型的保存时会产生装箱拆箱的操作,损失很大一部分性能
- 就算有时候我们有需要
List<object>
这样的容器,但是还是尽量写成List<object>
,写成ArrayList
会和其他List
显得不整齐
是这样没错,尤其是第二条,所以我们直接抛弃掉ArrayList
的写法实际上,ArrayList
和List<object>
的效率是一样的,用如下代码测试:
1 | System.Collections.ArrayList l0 = new System.Collections.ArrayList(); |
输出结果如下:
于是我们就不再考虑ArrayList了
List<object>
和List<T>
这里的T是我们自定义的一个结构体或类
至于这里到底是结构体还是类,测试结果相差很远。
结构体
先看结构体的情况:
1 | struct StructData |
接下来是测试代码:
1 | List<int> l3 = new List<int>(); |
多执行几次,运行结果如下:
可以看到,当我们打算用List<T>
存储结构体时,最好不要用List<object>
,因为在存储的时候必须进行装箱的操作,也就是把存储于栈的结构体保存到堆中,这会极大地损耗性能
类
如果T不是结构体而是一个我们手动new出来的对象,那么理论上就不存在装箱和拆箱的操作了,然后再试试
1 | // 类的声明 |
同样多执行几次,运行结果如下:
咦,List<MyClass>
的速度居然还不如List<object>
我也不太清楚为啥会这样,估计是List<MyClass>
存的时候需要进行类型检查,这一步消耗了一定的时间吧
总结
其实这一篇也没啥实际意义,在实际的应用中还是尽量用List<MyClass>
吧,既不用考虑装箱导致的性能损耗,又能保证类型安全,损失的部分性能也是可以接受的,除非某些对应能特别敏感的需求。
PS. 新的发现,在List<object>
和List<T>
的对比中,使用macOS下的monoDevelop产生的结果会比较整齐,在Windows10下使用VS2015产生的结果会比较不整齐,统计出来的时间起伏较大
下一篇开始正儿八经做游戏啦