39. C# -- 装箱拆箱性能对比(HashTable、ArraryList、List)

  • 装箱是将值类型转换为引用类型 ,拆箱是将引用类型转换为值类型也知道装箱与拆箱过程中将带来性能上的问题,但是在实际的项目中往往会忽略这个问题,将可能带来极大的效率上的问题。


  • 代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace CollectionsApplication
{
    /// <summary>
    /// 装箱拆箱(HashTable ArraryList List<T>)对比
    /// </summary>
    class Program
{
        static void Main(string[] args)
{
            while (true)
{
                Console.WriteLine("CycleNum:");   
                string strcCycleNum=Console.ReadLine ();
                int cycleNum= 0;
                if (!int.TryParse(strcCycleNum, out cycleNum))
{
                    Console.WriteLine("Input invalid!");
                    continue;
}
                HashTableCost(cycleNum);
                ArraryListCost(cycleNum);
                GenericCost(cycleNum);
}
}
        /// <summary>
        /// HashTable 开销测试
        /// </summary>
        /// <param name="cycleNum">循环次数</param>
        static void HashTableCost(int cycleNum)
{
            Stopwatch sw = new Stopwatch();
            Hashtable hs_Test = new Hashtable();
            sw.Start();
            for (int i = 0; i < cycleNum; i++)
{
                hs_Test.Add(i,i);
}
            sw.Stop();
            ConsoleInfo(cycleNum, "HashTableCost", sw.ElapsedMilliseconds);
}
        /// <summary>
        /// ArraryList 开销测试
        /// </summary>
        /// <param name="cycleNum">循环次数</param>
        static void ArraryListCost(int cycleNum)
{
            Stopwatch sw = new Stopwatch();
            ArrayList al_Test = new ArrayList();
            sw.Start();
            for (int i = 0; i < cycleNum; i++)
{
                al_Test.Add(i);
}
            sw.Stop();
            ConsoleInfo(cycleNum, "ArraryListCost", sw.ElapsedMilliseconds);
}
 
 
        /// <summary>
        /// 泛型 开销测试
        /// </summary>
        /// <param name="cycleNum">循环次数</param>
        static void GenericCost(int cycleNum)
{
            Stopwatch sw = new Stopwatch();
            List<int> lTest = new List<int>();
            sw.Start();
            for (int i = 0; i < cycleNum; i++)
{
                lTest.Add(i);
}
            sw.Stop();
            ConsoleInfo(cycleNum, "GenericCost", sw.ElapsedMilliseconds);
}
        /// <summary>
        /// 打印信息
        /// </summary>
        /// <param name="cycleNum">循环次数</param>
        /// <param name="methodName">方法名称</param>
        /// <param name="cost">开销</param>
        /// 
        static void ConsoleInfo(int cycleNum,string methodName,long cost)
{
            Console.WriteLine(methodName + "cyclenum:"+ cycleNum.ToString () +"cost (s)" + cost.ToString ());

}
}
}
  • 测试结果:

对于测试结果还是很惊讶,循环添加1000次,3者都为0毫秒,在10W与100W次的结果出现了鲜明的对比分别为305ms,86ms,9ms。差距不是一般的大。

 

对代码进行分析:

 

// HashTable : public virtual void Add(object key, object value); 

// 在Add的过程中进行了2次装箱

 hs_Test.Add(i, i);

HashTable.add()都会产生2次装箱。

 

// public virtual int Add(object value);

// 产生了一次装箱

 al_Test.Add(i);

ArraryList.add产生2次装箱。

 

// 由于lTest 指定了类型(List<int>)并没有产生装箱

lTest.Add(i);

List<int>没有产生装箱。

 

也可以通过IL对代码进行分析,这里就不再列出了。

 

总结

在对大量数据进行操作的时候一定要注意装箱与拆箱操作,可以用泛型代替的地方还是使用泛型吧。

 

在平时的一般项目中的细节也需要注意,毕竟细节决定成败,再NB的框架,也经不起这一片片的装箱与拆箱的轰炸。

 

(ps:隐式转换的时候要细心,在转换成字符串的时候习惯使用ToString(),毕竟是不产生装箱的。)

参考:
http://www.2cto.com/kf/201411/349779.html

你可能感兴趣的:(C#,对比,装箱拆箱)