欢迎来到代码驿站!

.NET代码

当前位置:首页 > 软件编程 > .NET代码

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

时间:2021-01-21 10:55:03|栏目:.NET代码|点击:
可能大家谈到反射面部肌肉都开始抽搐了吧!因为在托管语言里面,最臭名昭著的就是反射!它的性能实在是太低了,甚至在很多时候让我们无法忍受。不过不用那么纠结了,老陈今天就来分享一下如何来优化反射!

概述
本文涉及到的反射优化的途径有如下两种:

通过Delegate.CreateDelegate()创建委托进行优化
通过.NET4的动态运行时进行优化
如果您还知道其他更加有效的优化途径,请不吝赐教!

准备工作
今天我们总计要对比五种不同的调用对象成员的方式,也算是一种性能测评。

在开始之前,我们首先定义一个简单的对象和一个方法,以供测试之用:
复制代码 代码如下:

namespace ReflectionOptimization
{
public sealed class TestObject
{
public int Add(int a, int b)
{
// 简单演示
return a + b;
}
}
}

这个类非常简单,只提供了一个方法,这个方法返回两个整形的和。接下来我们看看执行时间测量的代码,很简单,想必您已经驾轻就熟了:
复制代码 代码如下:

private static double _Run(string description, Action<int, int> action, int a, int b)
{
if (action == null) throw new ArgumentNullException("action");

// 启动计时器
var stopwatch = Stopwatch.StartNew();

// 运行要测量的代码
action(a, b);

// 终止计时
stopwatch.Stop();

// 输出结果
Console.WriteLine("{0}: {1}", description, stopwatch.Elapsed.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));

// 返回执行时间
return stopwatch.Elapsed.TotalMilliseconds;
}

以上测量时间的方法返回了执行时间,因为我们要在后面用到这个值,在执行多次之后取个平均值,以求测试的公平性、权威性。

编码实现
首先我们来看看原生反射的实现:
复制代码 代码如下:

var obj = new TestObject();
var add = obj.GetType().GetMethod("Add");

for (var i = 0; i < _TIMES; i++) add.Invoke(obj, new object[] {a, b});

然后我们看看.NET4动态编程的实现:
复制代码 代码如下:

dynamic obj = new TestObject();

// 有木有发现这个代码超级简单?
for (var i = 0; i < _TIMES; i++) obj.Add(a, b);

最后我们看看如何使用委托来优化反射:
复制代码 代码如下:

// 委托
public delegate int AddMethod(int a, int b);

// 实现
var obj = new TestObject();
var objType = obj.GetType();
var add = objType.GetMethod("Add");
var d = (AddMethod)Delegate.CreateDelegate(typeof(AddMethod), obj, add);

for (var i = 0; i < _TIMES; i++) d(a, b);

上面的代码看起来多了几行,而且还需要自定义一个委托,写起来挺麻烦的。因此我们的测试代码里面还实现了另外一种形式,其实它也是委托:

var d = (Func<TestObject, int, int, int>)Delegate.CreateDelegate(typeof(Func<TestObject, int, int, int>), add);

测试总结
我们首先在Debug模式下将整个测试代码运行5遍,然后分别记录平均值,然后再到Release模式下重复该测试。

测试的过程不再阐述,测试结果整理如下:

Debug模式:

调用方式 第一次 第二次 第三次 第四次 第五次
Generic Call 1.022425 1.012885 0.990775 1.020950 1.046880
Reflection 147.489220 146.012010 142.690080 139.189335 141.663475
dynamic 9.645850 9.979965 9.307235 9.532665 9.730030
Func 1.201860 1.214800 1.170215 1.189280 1.239485
Delegate 1.062215 1.061635 1.067510 1.047180 1.075190

Release模式:

调用方式 第一次 第二次 第三次 第四次 第五次
Generic Call 0.745600 0.741365 0.722145 0.732630 0.725645
Reflection 141.778260 142.855410 142.346095 139.649990 138.541285
dynamic 9.631460 10.341850 9.284230 9.457580 9.060470
Func 0.882100 0.852680 0.875695 0.854655 0.831670
Delegate 0.710280 0.722465 0.723355 0.727175 0.693320

点评&结论:

  • 使用委托优化反射之后,其性能与直接调用相差无几,保持在同一个数量级之内,对性能要求极度苛刻时推荐此方案;
  • 显式委托(Delegate)和匿名委托(Func)性能差异非常不明显,但显式委托的性能还是好一点; 
  • 原生委托比直接调用慢出了两个数量级,性能差异达到了200倍之多!
  • .NET 4的动态编程语法相当简洁,其性能只比直接调用高出一个数量级,由于其语法相当简洁,我们推荐这种做法!
  • 原生反射技术在Debug模式和Release模式下没有太大差异,但其他方式有较为明显的优化效果(请思考为什么);
  • 虽然我们今天的测试不能完全意味着反射优化之后可以和直接调用相媲美,但至少可以从某种程度上击败那些个谣言――谁说反射就一定会慢(嘻嘻)!

代码下载:浅谈反射优化

上一篇:C#实现解析百度天气数据,Rss解析百度新闻以及根据IP获取所在城市的方法

栏    目:.NET代码

下一篇:C# Dictionary和SortedDictionary的简介

本文标题:浅谈.NET反射机制的性能优化 附实例下载

本文地址:http://www.codeinn.net/misctech/48846.html

推荐教程

广告投放 | 联系我们 | 版权申明

重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:914707363 | 邮箱:codeinn#126.com(#换成@)

Copyright © 2020 代码驿站 版权所有