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

 更新时间:2012年04月07日 10:41:27   作者:  
在进入解释型模版引擎的探讨之前,我决定先分享一下这篇博客。因为在解释型引擎里将会引入反射的概念来实现更多、更复杂的功能
可能大家谈到反射面部肌肉都开始抽搐了吧!因为在托管语言里面,最臭名昭著的就是反射!它的性能实在是太低了,甚至在很多时候让我们无法忍受。不过不用那么纠结了,老陈今天就来分享一下如何来优化反射!

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

通过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模式下没有太大差异,但其他方式有较为明显的优化效果(请思考为什么);
  • 虽然我们今天的测试不能完全意味着反射优化之后可以和直接调用相媲美,但至少可以从某种程度上击败那些个谣言——谁说反射就一定会慢(嘻嘻)!

代码下载:浅谈反射优化

相关文章

  • ASP.NET自带对象JSON字符串与实体类的转换

    ASP.NET自带对象JSON字符串与实体类的转换

    这篇文章主要介绍了ASP.NET自带对象JSON字符串与实体类的转换,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • ASP.NET Core应用错误处理之DeveloperExceptionPageMiddleware中间件呈现“开发者异常页面”

    ASP.NET Core应用错误处理之DeveloperExceptionPageMiddleware中间件呈现“开发者

    这篇文章主要给大家介绍了关于ASP.NET Core应用错误处理之DeveloperExceptionPageMiddleware中间件呈现“开发者异常页面”的相关资料,需要的朋友可以参考下
    2019-01-01
  • LINQ to XML的编程基础

    LINQ to XML的编程基础

    本文介绍了LINQ to XML的编程基础,即System.Xml.Linq命名空间中的多个LINQ to XML类,这些类都是LINQ to XML的支持类,它们使得处理xml比使用其他的xml工具容易得多。在本文中,着重介绍的是XElement、XAttribute和XDocument。
    2010-02-02
  • C#可以减少或不使用switch有什么方法

    C#可以减少或不使用switch有什么方法

    减少或不使用switch,大家有什么好的方法,使用工厂方法来处理,可以创建一个工厂接口,然后每个方法设计为一个工厂类,并实现工厂接口,感兴趣的朋友可以了解下
    2013-03-03
  • ASP.NET Core静态文件使用教程(9)

    ASP.NET Core静态文件使用教程(9)

    这篇文章主要为大家详细介绍了ASP.NET Core静态文件的使用教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • asp.net(C#)生成无限级别菜单

    asp.net(C#)生成无限级别菜单

    最近开发的一个项目中用到了无限级别菜单,因此将此代码贴出来,以供研究,开发环境为VS2008+SQL 2000。
    2010-03-03
  • .net6环境下使用RestSharp请求GBK编码网页乱码的解决方案

    .net6环境下使用RestSharp请求GBK编码网页乱码的解决方案

    这篇文章介绍了.net6环境下使用RestSharp请求GBK编码网页乱码的解决方案,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-12-12
  • C#图片截取压缩(百分比压缩/大小压缩)实现代码

    C#图片截取压缩(百分比压缩/大小压缩)实现代码

    为了娱乐写了个截取图片和压缩图片你的小工具:按照百分比压缩/制定大小压缩等等,感兴趣的朋友可以了解下啊,希望本文对你学些c#图片知识有所帮助
    2013-01-01
  • ASP.NET Core中的依赖问题解决方法示例

    ASP.NET Core中的依赖问题解决方法示例

    这篇文章主要为大家介绍了ASP.NET Core中的依赖问题解决方法示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • asp.net下PageMethods使用技巧

    asp.net下PageMethods使用技巧

    ASP.net AjAX中的PageMethods可以将静态页方法添加到 ASP.NET 页中并将其用作 Web 方法。然后,无需创建单独的 .asmx 文件即可从该页中的脚本调用这些方法,就好像这些方法是 Web 服务的一部分。特别是在一些交互流程不复杂而调用次数和方法又比较多的情况下更为方便。因为PageMethods不需要我们再添加另外的WEB服务或Page来处理请求。
    2008-03-03

最新评论