• 读书笔记-C#中装箱拆箱性能


    前言

      最近在看王涛大神的《你必须知道的.NET(第二版)》一书,嗯,首先膜拜一下….
     
      在书中的第五章-品味类型中,对装箱与拆箱一节感触很深,概念本身相信每一个程序猿都不陌生,装箱是将值类型转换为引用类型 ,拆箱是将引用类型转换为值类型(ps:不小心又背了一下书),也知道装箱与拆箱过程中将带来性能上的问题,但是在实际的项目中往往会忽略这个问题,将可能带来极大的效率上的问题。问题有多大,反正我哭过。
     
    简单对比测试
      在工作之余写了个简单的测试例子,以HashTable、ArraryList、List<T>进行了简单的对比。
     
      运行环境:Windows7_64(Cpu:i5; Ram:6GB)。
     
      代码如下:
     
    复制代码
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
     
    namespace Test
    {
        /// <summary>
        /// 装箱拆箱(HashTable ArraryList List<T>)对比
        /// </summary>
        class Program
        {
            static void Main(string[] args)
            {
                while (true)
                {
                    Console.WriteLine("循环次数:");
                    string strcCycleNum = Console.ReadLine();
                    int cycleNum = 0;
                    if (!int.TryParse(strcCycleNum, out cycleNum))
                    {
                        Console.WriteLine("无效输入!");
                        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.ToString() + "  开销(毫秒):" + 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(),毕竟是不产生装箱的。)
  • 相关阅读:
    Android使用注解代替枚举从而节省系统使用的内存开销
    android9.0系统适配遇到的问题
    android 图片上传图片 报Socket: Broken pipe
    android H5支付 网络环境未能通过安全验证,请稍后再试
    Error:Execution failed for task ':app:processDebugManifest'. Manifest merger failed with multiple errors, see logs
    NightWatch端到端测试
    JavaScript生成斐波那契数列
    Vue Material
    Jasmine
    Postman
  • 原文地址:https://www.cnblogs.com/gc2013/p/4089350.html
Copyright © 2020-2023  润新知