C#研究系列-List<>与ArrayList的几个研究心得及问题(上)

代码放在https://gist.github.com/921076 上了,看不到的请留言。

第一个心得,是我看某本书提到,IList用起来要比ArrayList快。

这里面用到了我上一篇博客提到的高精度计时器(在这里能看到代码 http://sunxiunan.com/?p=1829 )

在开始定义了两个类。


//---------------------

// public class List : IList, ICollection, IEnumerable, IList, ICollection, IEnumerable
class CFromList : List

{}

// public class ArrayList : IList, ICollection, IEnumerable, ICloneable
class CFromArrayList : ArrayList

{}

//---------------------

List和ArrayList的定义在注释中给出,可以看出来其实都差不多。ArrayList只是多了ICloneable,还少了几个泛型接口继承。

在后面代码中都用Add方法向list中添加int类型数据,然后通过foreach形式枚举数据,注意!枚举部分的代码是有问题的,我们在(下)中会提到。

这里还要推荐一个非常棒的工具ILSpy,是sharpdevelop开发的,强烈建议dotnet程序员都下载使用。

我把ILSpy disassemble出来的C#代码和IL代码分别列在后面。注意对于ArrayList的foreach语句,C#形式的代码与源代码有些差别(79 到96行),编译器加入一个IEnumerator enumerator2 = cFromArrayList.GetEnumerator();本地变量。

另外使用int num5 = (int)enumerator2.Current;这样访问iterator。而且还加入了IDisposable的finally部分。

再继续看IL代码部分,对于List形式,IL代码没有box装箱指令,而ArrayList在145行有个box指令,这是性能差别之一。
但是奇怪的是,在枚举部分,ILSpy生成的(以及ILDasm)IL代码,对于ArrayList和List而言,基本上差别不大,一样也有对 MoveNext和Current以及IDisposable接口的调用。

只不过ArrayList多出unbox和box的指令。

运行结果如我们所料,List要比ArrayList快不少。

但是我们在枚举部分的代码是有问题的,我明天在(下)中会介绍。

    // public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
    class CFromList : List<int>{}
    // public class ArrayList : IList, ICollection, IEnumerable, ICloneable
    class CFromArrayList : ArrayList{}
    public partial class Form1 : Form
    {
        private void button1_Click(object sender, EventArgs e)
        {
            CFromList list1 = new CFromList();
            CFromArrayList list2 = new CFromArrayList();
            ////////////////////////////
            HighResolutionTimer timera = new HighResolutionTimer();
            for (int i = 0; i < 100000; i++)
            {
                list1.Add(i - 99999);
            }
            Int64 reta = timera.Stop();
            ////////////////////////////
            HighResolutionTimer timerb = new HighResolutionTimer();
            for (int i = 0; i < 100000; i++)
            {
                list2.Add(i - 99999);
            }
            Int64 retb = timerb.Stop();
            ////////////////////////////
            int index = 0;
            HighResolutionTimer timer1 = new HighResolutionTimer();
            foreach (int elem1 in list1)
            {
                list1[index++] = elem1 + 99;
            }
            Int64 ret1 = timer1.Stop();
            ////////////////////////////
            index = 0;
            HighResolutionTimer timer2 = new HighResolutionTimer();
            foreach (int elem2 in list2)
            {
                list2[index++] = elem2 + 99;
            }
            Int64 ret2 = timer2.Stop();
            ////////////////////////////
      }
   }
///////////////////////////////////////////////////////
// result from ILSpy
CFromList cFromList = new CFromList();
CFromArrayList cFromArrayList = new CFromArrayList();
HighResolutionTimer highResolutionTimer = new HighResolutionTimer();
for (int i = 0; i < 100000; i++)
{
cFromList.Add(i - 99999);
}
long num = highResolutionTimer.Stop();
HighResolutionTimer highResolutionTimer2 = new HighResolutionTimer();
for (int i = 0; i < 100000; i++)
{
cFromArrayList.Add(i - 99999);
}
long num2 = highResolutionTimer2.Stop();
int num3 = 0;
HighResolutionTimer highResolutionTimer3 = new HighResolutionTimer();
foreach (int current in cFromList)
{
cFromList[num3++] = current + 99;
}
long num4 = highResolutionTimer3.Stop();
num3 = 0;
HighResolutionTimer highResolutionTimer4 = new HighResolutionTimer();
IEnumerator enumerator2 = cFromArrayList.GetEnumerator();
try
{
while (enumerator2.MoveNext())
{
int num5 = (int)enumerator2.Current;
cFromArrayList[num3++] = num5 + 99;
}
}
finally
{
IDisposable disposable = enumerator2 as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
long num6 = highResolutionTimer4.Stop();
//////////////////////////////////////////////////
// result from ILSpy IL format
IL_0000: nop
IL_0001: newobj instance void WindowsFormsApplication1.CFromList::.ctor()
IL_0006: stloc.0
IL_0007: newobj instance void WindowsFormsApplication1.CFromArrayList::.ctor()
IL_000c: stloc.1
IL_000d: newobj instance void WindowsFormsApplication1.HighResolutionTimer::.ctor()
IL_0012: stloc.2
IL_0013: ldc.i4.0
IL_0014: stloc.3
IL_0015: br.s IL_002b
// loop start (head: IL_002b)
IL_0017: nop
IL_0018: ldloc.0
IL_0019: ldloc.3
IL_001a: ldc.i4 99999
IL_001f: sub
IL_0020: callvirt instance void [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_0025: nop
IL_0026: nop
IL_0027: ldloc.3
IL_0028: ldc.i4.1
IL_0029: add
IL_002a: stloc.3
IL_002b: ldloc.3
IL_002c: ldc.i4 100000
IL_0031: clt
IL_0033: stloc.s 17
IL_0035: ldloc.s 17
IL_0037: brtrue.s IL_0017
// end loop
IL_0039: ldloc.2
IL_003a: callvirt instance int64 WindowsFormsApplication1.HighResolutionTimer::Stop()
IL_003f: stloc.s 4
IL_0041: newobj instance void WindowsFormsApplication1.HighResolutionTimer::.ctor()
IL_0046: stloc.s 5
IL_0048: ldc.i4.0
IL_0049: stloc.3
IL_004a: br.s IL_0065
// loop start (head: IL_0065)
IL_004c: nop
IL_004d: ldloc.1
IL_004e: ldloc.3
IL_004f: ldc.i4 99999
IL_0054: sub
IL_0055: box int32
IL_005a: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
IL_005f: pop
IL_0060: nop
IL_0061: ldloc.3
IL_0062: ldc.i4.1
IL_0063: add
IL_0064: stloc.3
IL_0065: ldloc.3
IL_0066: ldc.i4 100000
IL_006b: clt
IL_006d: stloc.s 17
IL_006f: ldloc.s 17
IL_0071: brtrue.s IL_004c
// end loop
IL_0073: ldloc.s 5
IL_0075: callvirt instance int64 WindowsFormsApplication1.HighResolutionTimer::Stop()
IL_007a: stloc.s 6
IL_007c: ldc.i4.0
IL_007d: stloc.s 7
IL_007f: newobj instance void WindowsFormsApplication1.HighResolutionTimer::.ctor()
IL_0084: stloc.s 8
IL_0086: nop
IL_0087: ldloc.0
IL_0088: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
IL_008d: stloc.s 18
.try {
IL_008f: br.s IL_00af
// loop start (head: IL_00af)
IL_0091: ldloca.s 18
IL_0093: call instance !0 [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0098: stloc.s 9
IL_009a: nop
IL_009b: ldloc.0
IL_009c: ldloc.s 7
IL_009e: dup
IL_009f: ldc.i4.1
IL_00a0: add
IL_00a1: stloc.s 7
IL_00a3: ldloc.s 9
IL_00a5: ldc.i4.s 99
IL_00a7: add
IL_00a8: callvirt instance void [mscorlib]System.Collections.Generic.List`1<int32>::set_Item(int32, !0)
IL_00ad: nop
IL_00ae: nop
IL_00af: ldloca.s 18
IL_00b1: call instance bool [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
IL_00b6: stloc.s 17
IL_00b8: ldloc.s 17
IL_00ba: brtrue.s IL_0091
// end loop
IL_00bc: leave.s IL_00cd
} // end .try
finally {
IL_00be: ldloca.s 18
IL_00c0: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
IL_00c6: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_00cb: nop
IL_00cc: endfinally
} // end handler
IL_00cd: nop
IL_00ce: ldloc.s 8
IL_00d0: callvirt instance int64 WindowsFormsApplication1.HighResolutionTimer::Stop()
IL_00d5: stloc.s 10
IL_00d7: ldc.i4.0
IL_00d8: stloc.s 7
IL_00da: newobj instance void WindowsFormsApplication1.HighResolutionTimer::.ctor()
IL_00df: stloc.s 11
IL_00e1: nop
IL_00e2: ldloc.1
IL_00e3: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
IL_00e8: stloc.s 19
.try {
IL_00ea: br.s IL_0114
// loop start (head: IL_0114)
IL_00ec: ldloc.s 19
IL_00ee: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_00f3: unbox.any int32
IL_00f8: stloc.s 12
IL_00fa: nop
IL_00fb: ldloc.1
IL_00fc: ldloc.s 7
IL_00fe: dup
IL_00ff: ldc.i4.1
IL_0100: add
IL_0101: stloc.s 7
IL_0103: ldloc.s 12
IL_0105: ldc.i4.s 99
IL_0107: add
IL_0108: box int32
IL_010d: callvirt instance void [mscorlib]System.Collections.ArrayList::set_Item(int32, object)
IL_0112: nop
IL_0113: nop
IL_0114: ldloc.s 19
IL_0116: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_011b: stloc.s 17
IL_011d: ldloc.s 17
IL_011f: brtrue.s IL_00ec
// end loop
IL_0121: leave.s IL_0140
} // end .try
finally {
IL_0123: ldloc.s 19
IL_0125: isinst class [mscorlib]System.IDisposable
IL_012a: stloc.s 20
IL_012c: ldloc.s 20
IL_012e: ldnull
IL_012f: ceq
IL_0131: stloc.s 17
IL_0133: ldloc.s 17
IL_0135: brtrue.s IL_013f
IL_0137: ldloc.s 20
IL_0139: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_013e: nop
IL_013f: endfinally
} // end handler
IL_0140: nop
IL_0141: ldloc.s 11
IL_0143: callvirt instance int64 WindowsFormsApplication1.HighResolutionTimer::Stop()
IL_0148: stloc.s 13


posted @ 2011-04-15 23:55  林志玲  阅读(3512)  评论(18编辑  收藏  举报