[.net泛型学习笔记之二]泛型的性能

一般都说,泛型能够提高程序的性能,理由有:

l         避免装箱和拆箱操作。比方:

    ArrayList list = new ArrayList();

    list.Add(123);        //需要装箱

    int i = (int)list[0]; //需要拆箱

l         类型检查是在编译时间进行,而不是在运行时间进行的。比方:

    ArrayList list = new ArrayList();

    list.Add("I am a string.");       

string i = (string)list[0]; //在运行时需要检查类型

 

本文主要对以上的理由进行验证,看看究竟是否真的如此,如果提高,究竟提高了多少。为此我们采用了以下方案测试:

 

测试方案 下载

样本

l         避免装箱和拆箱测试

1.         int in Arraylist vs. int in List<T>

2.         Large struct in ArrayList vs. Large class in ArrayList

3.         Large struct in ArrayList vs. large struct in List<T>

其中Large ClassLarge struct代码如下:

    class LargeDataClass

{ decimal A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z;}

    struct LargeDataStruct

{ decimal A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z;}

 

l         类型检查是在编译时间进行,而不是在运行时间进行的

1.         custom class in ArrayList vs. custom class in List<T>

2.         string in Arraylist vs. string in List<T>   (本测试的目的,由于字符串是一个特殊的引用类型,而且经常使用,所以专门测试一下。)

custom class采用上面的LargeDataClass类。

 

这里的样本参见了:

http://blog.joycode.com/sunmast/archive/2005/12/16/csharp_generic_misleading.aspx  

 

数据要求

每一个测试数据都测试3次,取平均值,并且剔除个别异常数据。

 

测试脚本

一般的测试脚本如下,在不同测试里,集合类型和元素的类型作相应修改就可以了。

    public static double Test1()

    {   GC.Collect();

        ArrayList list1 = new ArrayList();

        sw.Reset();       //sw是一个System.Diagnostics.Stopwatch对象

        sw.Start();

        for (int i = 0; i < Program.MaxCount; i++)

        {   LargeDataStruct data1 = new LargeDataStruct();

            list1.Add(data1);                                   //测试装箱

            LargeDataStruct data2 = (LargeDataStruct)list1[0];  //测试拆箱

        }

        sw.Stop();

        return sw.Elapsed.TotalSeconds;

}

 

测试结果 下载

P4 2.4GHz, 1G内存硬件,测试结果如下:

 

int in Arraylist

int in List<T>

large struct in ArrayList

large class in ArrayList

large struct in List<T>

large class in List<T>

string in ArrayList

string in List<T>

1000

0.0001134

0.000067

0.00148

0.000861

0.002366

0.000889

0.000459

0.000431

5000

0.0004195

0.0001952

0.006137

0.004077

0.016215

0.004753

0.002319

0.002125

10000

0.0007631

0.0002795

0.012613

0.008166

0.03255

0.008668

0.005103

0.005086

50000

0.0047294

0.0015961

0.136584

0.108376

0.137993

0.122591

0.024915

0.025379

100000

0.008883

0.0029012

0.337866

0.311848

0.278781

0.322081

0.050526

0.050124

500000

0.0541089

0.0169461

2.041508

1.989155

1.510633

2.014511

0.316258

0.314505

1000000

0.1205284

0.0333785

4.423767

4.147733

3.044961

4.120063

0.847025

0.837486

 

结果分析

l         避免装箱和拆箱测试

1.         int in Arraylist vs. int in List<T>
List<T>
ArrayList1-2倍。

2.         Large struct in ArrayList vs. Large class in ArrayList
后者比前者快一些,提高幅度在10%-50%之间

3.         Large struct in ArrayList vs. large struct in List<T>
10000以下,前者的速度是后者的2-3倍。但当50000以上,两者的数据开始接近,当数据量>100000,后者的速度超过了前者,并且优势越来越大。产生这种情况的原因不明。

 

1个、第2个的情况符合一般的预期。也符合书本上对.net泛型的宣传,但问题是,第3个为何情况如此奇怪?

 

l         类型检查是在编译时间进行,而不是在运行时间进行的

1.         custom class in ArrayList vs. custom class in List<T>  custom class large class
前者比后者速度稍快,在10%范围以内,故总体相当。

2.         string in Arraylist vs. string in List<T>
后者比前者速度稍快,在10%范围以内,故总体相当。

 

这个结论和预期稍微有些出入,看来对于引用类型的对象,泛型并没有能够提高速度。

 

总结

对于泛型在的性能情况,似乎可以得出以下结论:

1)  对于int这样的简单值类型,泛型能够提高1-2倍的速度。

2)  对于复杂的值类型,在集合数据小于50000情况下,泛型的速度慢1-2倍。但在50000以上,泛型的速度将超过传统方式(但原因何在,是否是由其他原因造成,比如:垃圾收集等)。由于在实际的情况中,我们几乎不太可能把复杂的值类型放到集合中去(因为在这种情况下,修改值类型中的变量或属性不太方便,而且容易出错),所以这里的疑问或许也不用太去深究了。

3)  对于引用(Reference)类型,泛型和传统的方式速度相当。

 

 

posted on 2006-05-25 23:39  microsheen  阅读(4298)  评论(7编辑  收藏  举报