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

简介:

由于频繁地使用反射会影响性能,所以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

作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
编译器 数据处理 C#
C#中的异步流:使用IAsyncEnumerable<T>和await foreach实现异步数据迭代
【1月更文挑战第10天】本文介绍了C#中异步流的概念,并通过使用IAsyncEnumerable<T>接口和await foreach语句,详细阐述了如何异步地迭代数据流。异步流为处理大量数据或需要流式处理数据的场景提供了一种高效且非阻塞性的方法,使得开发者能够更优雅地处理并发和数据流问题。
|
C#
WPF中实现多选ComboBox控件
原文:WPF中实现多选ComboBox控件 在WPF中实现带CheckBox的ComboBox控件,让ComboBox控件可以支持多选。 将ComboBox的ItemsSource属性Binding到一个Book的集合, public class Book { ...
3796 0
|
机器学习/深度学习 数据采集 人工智能
动手实践:从零开始训练AI模型的全面指南
【7月更文第14天】随着人工智能技术的飞速发展,训练AI模型已成为科研、工程乃至创业领域的热门技能。本文旨在为初学者提供一个清晰、实用的指南,带领大家从零开始,了解并实践如何训练一个人工智能模型。我们将以一个简单的线性回归任务为例,逐步深入,探讨数据预处理、模型构建、训练过程及评估方法,最后展示如何使用Python和深度学习库PyTorch实现这一过程。
6779 0
|
自然语言处理 安全 Java
【JDK8/11/17流行版本对比详解】(三)
【JDK8/11/17流行版本对比详解】
371 0
java.io.IOException: Requested internal only, but not enough space
java.io.IOException: Requested internal only, but not enough space
1008 0
|
关系型数据库 MySQL 数据安全/隐私保护
MySQL索引的作用(索引的优缺点)
MySQL索引的作用(索引的优缺点)
514 0
|
存储 缓存 关系型数据库
【MySQL】myisam_sort_buffer_size=32M,是干什么的?底层原理是什么?
【MySQL】myisam_sort_buffer_size=32M,是干什么的?底层原理是什么?
813 0
|
PyTorch 算法框架/工具
在pytorch环境下使用jupyter的步骤
在pytorch环境下使用jupyter的步骤
在pytorch环境下使用jupyter的步骤
|
SQL 数据库
SQL Server如何还原误删除的数据-操作篇(二)
我们使用的SQL Server 2017作操作平台,在数据库AdventureWorks中新建一张表并插入部分数据,然后将这些数据删除,再通过一系列的操作看是否能将这些数据恢复成我们最开始插入的数据。
SQL Server如何还原误删除的数据-操作篇(二)
|
存储 XML JSON
Python基础--dict(或对象)与json之间的区别和互相转化
Python开发中字典和 json的概念与相互转化
1357 0

热门文章

最新文章