• 【转】反射调用性能比较


    原文:http://www.cnblogs.com/tianzhiliang/archive/2012/06/29/2570275.html

    下面通过编写Demo的方式,验证各种反射的性能。

    1、传统方式反射

    复制代码
     1             Type t = typeof(Person);
     2             MethodInfo methodInfo = t.GetMethod("Say");
     3             Person person = new Person();
     4             string word = "hello";
     5             Person p = null;
     6             object[] param = new object[] { word, p, 3 };
     7             int TestTimes = 1000000; //测试次数,可自行调节看效果
     8 
     9             #region 传统方式反射
    10             try
    11             {
    12                 Stopwatch watch = new Stopwatch();
    13                 watch.Start();
    14                 for (int i = 0; i < TestTimes; i++)
    15                 {
    16                     methodInfo.Invoke(person, param);
    17                 }
    18                 watch.Stop();
    19                 Console.WriteLine(TestTimes.ToString() + " times invoked by Reflection: " + watch.ElapsedMilliseconds + "ms");
    20             }
    21             catch (System.Exception ex)
    22             {
    23                 Console.WriteLine("传统方式反射 直接错误:" + ex.Message);
    24                 Console.WriteLine("传统方式反射 内部错误:" + ex.InnerException.Message);
    25             }
    26             #endregion
    复制代码

    2、实例化反射

    复制代码
     1             #region 实例化反射
     2             try
     3             {
     4                 //Stopwatch watch = new Stopwatch();
     5                 //watch.Start();
     6                 //for (int i = 0; i < TestTimes; i++)
     7                 //{
     8                 //    Assembly Asm = Assembly.Load("testInvoke");//反射出空间 
     9                 //    Type type = Asm.GetType("testInvoke.Person");//反射出空间下的类 
    10                 //    object AssClas = Activator.CreateInstance(type);//动态实例化反射回来的指定空间下的指定类 
    11                 //    IPerson objPerson = (Person)AssClas; ////转换为接口类型 
    12                 //    objPerson.Say(ref word, out p, 3);
    13                 //}
    14                 //watch.Stop();
    15                 //Console.WriteLine(TestTimes.ToString() + " times invoked by InstanceReflection@1: " + watch.ElapsedMilliseconds + "ms");
    16 
    17                 Assembly Asm = Assembly.Load("testInvoke");//反射出空间
    18                 Type type = Asm.GetType("testInvoke.Person");//反射出空间下的类
    19                 object AssClas = Activator.CreateInstance(type);//动态实例化反射回来的指定空间下的指定类 
    20                 IPerson objPerson = (Person)AssClas; //转换为接口类型 
    21                 Stopwatch watch = new Stopwatch();
    22                 watch.Start();
    23                 for (int i = 0; i < TestTimes; i++)
    24                 {
    25                     objPerson.Say(ref word, out p, 3);
    26                 }
    27                 watch.Stop();
    28                 Console.WriteLine(TestTimes.ToString() + " times invoked by InstanceReflection@2: " + watch.ElapsedMilliseconds + "ms");
    29 
    30             }
    31             catch (System.Exception ex)
    32             {
    33                 Console.WriteLine("实例化反射 错误:" + ex.Message);
    34             }
    35             #endregion
    复制代码

    3、快速反射

    复制代码
     1             #region 快速反射
     2             try
     3             {
     4                 Stopwatch watch1 = new Stopwatch();
     5                 FastInvoke.FastInvokeHandler fastInvoker = FastInvoke.GetMethodInvoker(methodInfo);
     6                 watch1.Start();
     7                 for (int i = 0; i < TestTimes; i++)
     8                 {
     9                     fastInvoker(person, param);
    10                 }
    11                 watch1.Stop();
    12                 Console.WriteLine(TestTimes.ToString() + " times invoked by FastInvoke: " + watch1.ElapsedMilliseconds + "ms");
    13             }
    14             catch (System.Exception ex)
    15             {
    16                 Console.WriteLine("快速反射 错误:" + ex.Message);
    17             }
    18             #endregion
    复制代码
    复制代码
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Reflection.Emit;
      6 using System.Reflection;
      7 
      8 namespace testInvoke
      9 {
     10     class FastInvoke
     11     {
     12         public delegate object FastInvokeHandler(object target, object[] paramters);
     13 
     14         static object InvokeMethod(FastInvokeHandler invoke, object target, params object[] paramters)
     15         {
     16             return invoke(null, paramters);
     17         }
     18 
     19         public static FastInvokeHandler GetMethodInvoker(MethodInfo methodInfo)
     20         {
     21             DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo.DeclaringType.Module);
     22             ILGenerator il = dynamicMethod.GetILGenerator();
     23             ParameterInfo[] ps = methodInfo.GetParameters();
     24             Type[] paramTypes = new Type[ps.Length];
     25             for (int i = 0; i < paramTypes.Length; i++)
     26             {
     27                 if (ps[i].ParameterType.IsByRef)
     28                     paramTypes[i] = ps[i].ParameterType.GetElementType();
     29                 else
     30                     paramTypes[i] = ps[i].ParameterType;
     31             }
     32             LocalBuilder[] locals = new LocalBuilder[paramTypes.Length];
     33 
     34             for (int i = 0; i < paramTypes.Length; i++)
     35             {
     36                 locals[i] = il.DeclareLocal(paramTypes[i], true);
     37             }
     38             for (int i = 0; i < paramTypes.Length; i++)
     39             {
     40                 il.Emit(OpCodes.Ldarg_1);
     41                 EmitFastInt(il, i);
     42                 il.Emit(OpCodes.Ldelem_Ref);
     43                 EmitCastToReference(il, paramTypes[i]);
     44                 il.Emit(OpCodes.Stloc, locals[i]);
     45             }
     46             if (!methodInfo.IsStatic)
     47             {
     48                 il.Emit(OpCodes.Ldarg_0);
     49             }
     50             for (int i = 0; i < paramTypes.Length; i++)
     51             {
     52                 if (ps[i].ParameterType.IsByRef)
     53                     il.Emit(OpCodes.Ldloca_S, locals[i]);
     54                 else
     55                     il.Emit(OpCodes.Ldloc, locals[i]);
     56             }
     57             if (methodInfo.IsStatic)
     58                 il.EmitCall(OpCodes.Call, methodInfo, null);
     59             else
     60                 il.EmitCall(OpCodes.Callvirt, methodInfo, null);
     61             if (methodInfo.ReturnType == typeof(void))
     62                 il.Emit(OpCodes.Ldnull);
     63             else
     64                 EmitBoxIfNeeded(il, methodInfo.ReturnType);
     65 
     66             for (int i = 0; i < paramTypes.Length; i++)
     67             {
     68                 if (ps[i].ParameterType.IsByRef)
     69                 {
     70                     il.Emit(OpCodes.Ldarg_1);
     71                     EmitFastInt(il, i);
     72                     il.Emit(OpCodes.Ldloc, locals[i]);
     73                     if (locals[i].LocalType.IsValueType)
     74                         il.Emit(OpCodes.Box, locals[i].LocalType);
     75                     il.Emit(OpCodes.Stelem_Ref);
     76                 }
     77             }
     78 
     79             il.Emit(OpCodes.Ret);
     80             FastInvokeHandler invoder = (FastInvokeHandler)dynamicMethod.CreateDelegate(typeof(FastInvokeHandler));
     81             return invoder;
     82         }
     83 
     84         private static void EmitCastToReference(ILGenerator il, System.Type type)
     85         {
     86             if (type.IsValueType)
     87             {
     88                 il.Emit(OpCodes.Unbox_Any, type);
     89             }
     90             else
     91             {
     92                 il.Emit(OpCodes.Castclass, type);
     93             }
     94         }
     95 
     96         private static void EmitBoxIfNeeded(ILGenerator il, System.Type type)
     97         {
     98             if (type.IsValueType)
     99             {
    100                 il.Emit(OpCodes.Box, type);
    101             }
    102         }
    103 
    104         private static void EmitFastInt(ILGenerator il, int value)
    105         {
    106             switch (value)
    107             {
    108                 case -1:
    109                     il.Emit(OpCodes.Ldc_I4_M1);
    110                     return;
    111                 case 0:
    112                     il.Emit(OpCodes.Ldc_I4_0);
    113                     return;
    114                 case 1:
    115                     il.Emit(OpCodes.Ldc_I4_1);
    116                     return;
    117                 case 2:
    118                     il.Emit(OpCodes.Ldc_I4_2);
    119                     return;
    120                 case 3:
    121                     il.Emit(OpCodes.Ldc_I4_3);
    122                     return;
    123                 case 4:
    124                     il.Emit(OpCodes.Ldc_I4_4);
    125                     return;
    126                 case 5:
    127                     il.Emit(OpCodes.Ldc_I4_5);
    128                     return;
    129                 case 6:
    130                     il.Emit(OpCodes.Ldc_I4_6);
    131                     return;
    132                 case 7:
    133                     il.Emit(OpCodes.Ldc_I4_7);
    134                     return;
    135                 case 8:
    136                     il.Emit(OpCodes.Ldc_I4_8);
    137                     return;
    138             }
    139 
    140             if (value > -129 && value < 128)
    141             {
    142                 il.Emit(OpCodes.Ldc_I4_S, (SByte)value);
    143             }
    144             else
    145             {
    146                 il.Emit(OpCodes.Ldc_I4, value);
    147             }
    148         }
    149     }
    150 }
    复制代码

    4、不用反射,直接调用

    复制代码
     1             #region 直接调用
     2             try
     3             {
     4                 Stopwatch watch2 = new Stopwatch();
     5                 watch2.Start();
     6                 for (int i = 0; i < TestTimes; i++)
     7                 {
     8                     person.Say(ref word, out p, 3);
     9                 }
    10                 watch2.Stop();
    11                 Console.WriteLine(TestTimes.ToString() + " times invoked by DirectCall: " + watch2.ElapsedMilliseconds + "ms");
    12             }
    13             catch (System.Exception ex)
    14             {
    15                 Console.WriteLine("直接调用 错误:" + ex.Message);
    16             }
    17             #endregion
    复制代码

    以上4种调用方式,100万次调用结果如下:

    所以得出以下结论:

    1. 不用反射,直接调用,效率最高。

    2. 实例化反射,效率次之。

    3. 快速反射,效率次之。

    4. 传统反射,效率最差。

    以上调用方式,后3种调用方式虽然效率有先后,但性能在一个数量级上,与传统反射相比,优越性较明显。

    另外补充一点,实例化反射如果算上创建实例的性能损耗,试验结果如下图:

    所以,如果需要频繁创建实例,建议不要采用实例化反射。

    源码下载:files.cnblogs.com/tianzhiliang/testInvoke.rar

  • 相关阅读:
    Android开发技术周报 Issue#39
    Android开发技术周报 Issue#40
    Android开发技术周报 Issue#41
    js删除最后一个字符串方法
    Firefox 插件 JSview是一套比较实用的JS,CSS文件查看工具,很方便,很快捷地查看页面引用了哪些文件,作为Web前端开发者是一套必备的插件,由于Firefox升级过快,插件很快不兼容了,这里对插件做了一些调整,可以兼容最新Firefox浏览器(目前FireFox 21)
    IT人常用的网站
    Jquery,全选,反选,
    Vue.js基础(二)
    Vue.js基础(一)
    Vue.js模拟百度下拉框
  • 原文地址:https://www.cnblogs.com/luofuxian/p/2593830.html
Copyright © 2020-2023  润新知