比较一下以“反射”和“表达式”执行方法的性能差异
由于频繁地使用反射会影响性能,所以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
- 回归分析技术|机器学习
- 用PHP蜘蛛做旅游数据分析
- 一秒找出用时间和随机数生成的上传文件名
- Java之集合的遍历与迭代器
- Java之字符串String,StringBuffer,StringBuilder
- JavaScript深入浅出补充——(一)数据类型,表达式和运算符
- Oracle数据库(一)概述、基础与简单操作
- Oracle数据库(二)常用关键字以及函数
- Oracle数据库(三)表操作,连接查询,分页
- 正式学习第一天下午——基础标签及其属性
- 正式学习第二天上午——常用标签及列表 0605
- Java之面向对象例子(三) 多态,重写,重载,equals()方法和toString()方法的重写
- Java之IO流补充
- JavaWeb 例子 JDBC+JSP登陆注册留言板
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 如何将炫酷的报表直接截图发送邮件——在Superset 0.37使用Schedule Email功能
- Kettle构建Hadoop ETL实践(五):数据抽取
- Kafka监控必备——Kafka-Eagle 2.0.2正式发布
- iOS Universal link 入门指南
- Flutter基础widgets教程-CupertinoAlertDialog篇
- Flutter基础widgets教程-cupertinoActivityIndicator篇
- Flutter基础widgets教程-Align篇
- 深入理解Linux内核进程上下文切换
- 面对疾风吧!io_uring 优化 nginx 实战演练
- 奇技淫巧:在 ssh 里面把服务器的文本复制到本地电脑
- 【计算机网络】学习笔记,第一篇:概述(谢希仁版)
- 【Objective-C】Objective-C语言的动态性
- Python解构与封装
- 关于内网穿透:NPS神器
- 【填坑系列】Python习题集