`
pcajax
  • 浏览: 2162255 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

比较一下以“反射”和“表达式”执行方法的性能差异【转】

 
阅读更多

由于频繁地使用反射会影响性能,所以ASP.NET MVC采用了表达式树的方式来执行目标Action方法。具体来说,ASP.NET MVC会构建一个表达式来体现针对目标Action方法的执行,并且将该表达式编译成可执行代码。编译后的可执行代码体现为一个委托对象,该委托对象会被缓存起来以用于针对同一个Action方法的执行。为了让大家能够和直观地理解两种(直接利用反射和利用表达式编译后的委托对象)方法执行在性能上的差异,我们来做一个简单的实例演示。我们在一个控制台应用中定义了如下一个Foobar类型,它的Invoke方法就是我们需要测试的目标方法。简单起见,我们没有为它定义任何参数,方法本身也不需要执行任何具体操作。

   1: public class Foobar
   2: {
   3:     public void Invoke(){}
   4: }

具体的测试程序如下所示。三个静态属性Target、Method和Executor分别代表执行的目标对象、目标方法和表达式编译后生成的委托对象,后者通过调用静态方法CreateExecutor方法创建。

   1: class Program
   2: {
   3:  
   4:     public static Foobar Target { get; private set; }
   5:     public static MethodInfo Method { get; private set; }
   6:     public static Action<Foobar> Executor { get; private set; }
   7:  
   8:     private static object[] args = new object[0];
   9:  
  10:     private static Action<Foobar> CreateExecutor(MethodInfo method)
  11:     { 
  12:         ParameterExpression target = Expression.Parameter(typeof(Foobar),"target");
  13:         Expression expression = Expression.Call(target, method);
  14:         return Expression.Lambda<Action<Foobar>>(expression, target).Compile();
  15:     }
  16:  
  17:     static Program()
  18:     {
  19:         Target = new Foobar();
  20:         Method = typeof(Foobar).GetMethod("Invoke");
  21:         Executor = CreateExecutor(Method);
  22:     }
  23:  
  24:     static void Main()
  25:     {
  26:         Console.WriteLine("{0,-10}{1,-12}{2}", "Times", "Reflection", "Expression");
  27:         Test(100000);
  28:         Test(1000000);
  29:         Test(10000000);
  30:     }
  31:  
  32:     private static void Test(int times)
  33:     {
  34:         Stopwatch stopwatch = new Stopwatch();
  35:  
  36:         stopwatch.Start();           
  37:         for (int i = 0; i < times; i++)
  38:         {
  39:             Method.Invoke(Target, args);
  40:         }
  41:         long elapsed1 = stopwatch.ElapsedMilliseconds;           
  42:  
  43:         stopwatch.Restart();
  44:         for (int i = 0; i < times; i++)
  45:         {
  46:             Executor(Target);
  47:         }
  48:         long elapsed2 = stopwatch.ElapsedMilliseconds;
  49:  
  50:         Console.WriteLine("{0,-10}{1,-12}{2}", times, elapsed1, elapsed2);
  51:     }
  52: }

测试方法Test的参数times表示我们执行目标方法的次数。在该方法中,我们调用MethodInfo对象的Invoke方法以反射的形式执行目标方法,然后利用Executor属性表示的委托对象来执行目标方法,并将它们执行的时间(以毫秒为单位)输出来。在作为程序入口的Main方法中,我们先后三个调用Test方法,并将执行目标方法的次数分别设置为100,000(十万)、1,000,000(百万)和10,000,000(千万)。运行程序后我们会在控制台上得到如下所示的输出结果,可以看出直接采用反射方式执行某个方法确实在性能上要差一些,但是差异其实不算明显。很多人总是觉得在程序中使用反射会对性能造成很大的影响,其实在我看来在很多情况下反射本身都不是造成性能瓶颈的元凶。

   1: Times      Reflection     Expression
   2: 100000     34             2
   3: 1000000    273            28
   4: 10000000   2627           284
分享到:
评论

相关推荐

    提升反射的性能(有用,启发)

    "方法的直接调用,反射调用与……Lambda表达式调用"这一篇可能比较了不同调用方式的性能差异,包括直接调用、反射调用和使用Lambda表达式调用。Lambda表达式可以提供一种更简洁、更高效的代码执行方式,尤其是在需要...

    C# 性能分析 反射 VS 配置文件 VS 预编译

    本文将探讨三种常见的代码操作技术:反射、配置文件和预编译,并通过比较它们的性能来分析各自的特点和适用场景。 **反射** 反射是.NET框架中的一个强大特性,它允许程序在运行时检查自身并动态执行代码。反射可以...

    【ASP.NET编程知识】浅谈.NET反射机制的性能优化 附实例下载.docx

    3. 反射调用在Debug和Release模式下的性能差异不大,但远低于其他几种方式。在需要优化性能的场合,应避免过度依赖反射,尤其是频繁调用的情况。 为了优化反射的性能,可以采取以下策略: 1. 使用预编译的委托:...

    浅谈.NET反射机制的性能优化 附实例下载

    然而,反射的使用通常伴随着性能损失,因为它涉及动态类型查找和方法调用,这比编译时静态绑定要慢得多。在本文中,我们将探讨两种主要的.NET反射性能优化策略,并通过实例代码展示它们的实现。 1. **通过Delegate....

    Java编程性能优化技巧有哪些共7页.pdf.zip

    1. **选择合适的数据结构**:根据实际需求选择最高效的数据结构,如ArrayList与LinkedList在不同场景下的性能差异,HashMap与TreeMap的查找速度等,都是优化的关键。 2. **避免过度使用同步**:虽然同步可以保证...

    从C++编程转到Java编程.rar

    C++起源于C语言,强调性能和底层控制,常用于系统编程、游戏开发和高性能计算。而Java则以“一次编写,到处运行”为理念,其跨平台特性使其在企业级应用、Web服务和移动开发(尤其是Android)中广泛应用。 1. 类型...

    jdk1.8中文版和英文版

    10. **反射API增强**:JDK 1.8对反射API进行了增强,比如`MethodHandle`和`MethodType`,提供了更高效和灵活的反射操作。 对于中文版和英文版的JDK 1.8,主要区别在于安装界面和文档的语言差异。中文版对于中文用户...

    jdk6和jdk8 64位 亲测 没有问题

    它是Java平台的一个里程碑,引入了许多新特性以提升开发者效率和应用程序性能。其中一些关键改进包括: 1. **泛型的增强**:JDK6对泛型的支持更加完善,允许类型推断,使得代码更简洁,减少类型转换的错误。 2. **...

    Java与C#比较研究 (2).pdf

    此外,它们都有丰富的库支持,如Java的Java Standard Edition(Java SE)和Java Enterprise Edition(Java EE),以及C#的.NET Framework,提供了大量预定义的类和方法,方便开发者快速构建应用程序。 在多线程方面...

    java面试题 IBM,交通银行等一些外包的面试题,(8K左右)

    - ArrayList与LinkedList:理解它们的实现方式和性能差异。 - HashMap与TreeMap:知道它们的内部工作原理和排序特性。 - HashSet与LinkedHashSet:比较其存储和遍历的不同。 3. **多线程**: - 线程创建:通过...

    Java——jdk1.8(64位和32位)

    7. **方法引用来替代反射**:Java 8引入了方法引用,它允许直接引用已存在的方法,而无需通过反射API,简化了代码并提高了性能。 8. **默认方法**:接口在Java 8中引入了默认方法,允许接口定义默认实现,这样可以...

    115个Java面试题和答案

    - **ArrayList和LinkedList**:了解它们在存储和操作上的性能差异。 - **HashSet和HashMap**:哈希算法在集合中的应用,以及键值对的概念。 7. **多线程**: - **Thread类和Runnable接口**:创建线程的两种方式...

    Java极品学习资料

    - 示例代码展示如何使用`equals`方法比较字符串。 #### 七、IO **字节流复制文件** - 使用字节流读取文件并将其写入新文件。 - 示例代码展示如何使用字节流复制文件。 **怎么删除带内容的文件夹** - 需要递归删除...

    Ruby程序设计

    继承机制允许子类继承父类的属性和方法,同时可以覆盖或扩展它们。特殊方法,如初始化方法`initialize`和访问器方法`attr_accessor`,简化了类的实现。Ruby的动态特性允许在运行时修改类的行为,这在元编程和框架...

    2.Java集合与数据结构.rar

    Java中,对象的比较可以通过重写`equals()`和`hashCode()`方法来实现。`Comparable`接口用于自定义比较逻辑,而`Comparator`接口则提供外部比较功能。 7. **Map和Set**: `Map`接口存储键值对,`Set`接口存储不...

    jdk1.8中文api文档.rar

    - `java.lang.invoke` 包提供了更强大的反射能力,如动态方法调用 (`MethodHandle`) 和方法类型 (`MethodType`)。 通过阅读 JDK 1.8 中文 API 文档,开发者可以深入了解以上特性的细节和使用方法,以及 Java 核心...

    java语言程序设计基础篇原书第六版 课后习题答案

    - **继承**:一个类可以继承另一个类的属性和方法,实现代码复用。 - **多态**:同一种行为在不同对象上有不同的表现形式,如方法重写和接口实现。 - **访问修饰符**:public、private、protected和默认访问级别...

    大公司的Java面试题集45225.doc

    - **反射**:反射的概念,如何通过反射获取类信息、创建对象、调用方法等。 - **JVM内存模型**:堆、栈、方法区、本地方法栈等区域的作用和GC机制。 - **Java 8新特性**:Lambda表达式、Stream API、Optional类等。 ...

    高清彩版 Writing High-Performance NET Code(2nd))

    - **基准测试**:通过基准测试可以客观地比较不同实现方案的性能差异。 - **实用工具**:介绍了多种实用工具,如 Profiler、PerfView 等,用于性能监控和分析。 #### 内存管理 - **内存分配**:详细讨论了如何有效...

    MSDN_C#编程指南

    - **类和方法**:程序的基本构建单元是类,类中包含方法和其他成员。 #### 四、命令行参数 - **读取参数**:通过`args`数组可以从命令行读取输入参数。 - **处理参数**:通常需要解析这些参数来执行特定的操作或...

Global site tag (gtag.js) - Google Analytics