可能大家谈到反射面部肌肉都开始抽搐了吧!因为在托管语言里面,最臭名昭著的就是反射!它的性能实在是太低了,甚至在很多时候让我们无法忍受。不过不用那么纠结了,老陈今天就来分享一下如何来优化反射!
概述
本文涉及到的反射优化的途径有如下两种:
通过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模式下重复该测试。
测试的过程不再阐述,测试结果整理如下:
调用方式
第一次
第二次
第三次
第四次
第五次
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
调用方式
第一次
第二次
第三次
第四次
第五次
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.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模式:
Release模式:
点评&结论:
- 使用委托优化反射之后,其性能与直接调用相差无几,保持在同一个数量级之内,对性能要求极度苛刻时推荐此方案;
- 显式委托(Delegate)和匿名委托(Func)性能差异非常不明显,但显式委托的性能还是好一点;
- 原生委托比直接调用慢出了两个数量级,性能差异达到了200倍之多!
- .NET 4的动态编程语法相当简洁,其性能只比直接调用高出一个数量级,由于其语法相当简洁,我们推荐这种做法!
- 原生反射技术在Debug模式和Release模式下没有太大差异,但其他方式有较为明显的优化效果(请思考为什么);
- 虽然我们今天的测试不能完全意味着反射优化之后可以和直接调用相媲美,但至少可以从某种程度上击败那些个谣言——谁说反射就一定会慢(嘻嘻)!
代码下载:浅谈反射优化
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
暂无评论...
更新日志
2024年11月29日
2024年11月29日
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]