如何详细说明 NET Core/Framework创建委托来大大提高反射调用的性能
前言
反射性损伤的表现大家都知道,但是不得不反思的时候怎么办?当你真的被问题逼的时候,你还是可以找到解决办法的。
反射是一项非常重要的技术,但它的性能比直接调用慢得多,因此如何优化反射性能成为必须面对的问题。目前优化反射性能最常用的方法是使用委托:以委托的方式调用需要反射调用的方法(或属性或字段)。
为反射的方法创建一个委托,然后调用该委托将提高几乎直接调用方法本身的性能。(当然,Emit也可以帮助我们显著提高性能,但是得到可以直接调用的委托不是更方便吗?)
性能比较数据
没有什么比数据更有说服力了(注意最后两行有秒)
也许我需要解释五行数据的含义:
直接调用(应该没有比直接调用函数本身更好的了)。使用与直接调用的方法相同的函数进行委托(目的是查看与调用方法本身相比是否有性能损失。从数据来看,损失很小)。本文的重点是从反射方法创建一个委托,然后调用这个委托(参见,性能与直接调用没有太大区别)首先反射方法。然后一直调用这个方法(最后可以看到反射本身对性能的伤害,是性能损失的50倍以上)。不使用缓存,从头反射调用得到的方法(性能损失100倍以上)是下面的测试代码,可以更好的理解上面数据的含义:
使用系统;使用系统。诊断;使用系统。反思;命名空间walterlv.demo {公共类程序{ static void main(string[]args){//是调用的目标实例。var实例=new Stubclass();//使用反射找到的方法。var方法=typeof(StubClass)。GetMethod(name of)(Stubclass。Test),new[]{ type of(int)});断言。IsNotNull(方法);//通过反映找到的方法来创建委托。var func=instance methodbuilderint,int。CreateInstanceMethod(实例,方法);//与被测方法功能相同的纯委托。Funcint,int pureFunc=value=value//测试次数。var计数=10000000;//直接打电话。var watch=新秒表();看着。start();for(var I=0;我数;i ) { var结果=实例。测试(5);}观看。stop();console . write line($ ' { watch . theated }-{ count }次-直接调用');//用相同的函数调用Func。看着。restart();for(var I=0;我数;i ) { var结果=PureFunc(5);}观看。stop();console . write line($ ' { watch . approach }-{ count } times-使用相同函数的Func调用');//由反射创建的委托调用。看着。restart();for(var I=0;我数;i ) { var结果=func(5);}观看。stop();console . write line($ ' { watch . theated }-{ count }次-反射创建的委托调用');//使用反射的方法缓存调用。看着。restart();for(var I=0;我数;i ) { var结果=方法。Invoke(实例,新对象[]{ 5 });}观看。stop();控制台。writeline ($' {watch。已用时间}-{count}次-使用反射的方法缓存调用');//使用反射直接调用。看着。restart();for(var I=0;我数;i ) { var result=typeof(StubClass)。GetMethod(name of)(Stubclass。Test),new[] { typeof(int) })?Invoke(实例,新对象[]{ 5 });}观看。stop();console . write line($ ' { watch . theated }-{ count }次-直接用反射调用');}私有类Stubclass { public int Test(int I){ return I;如何实现}}}}
实现的关键在于方法。CreateDelegate方法。此方法在中可用。NET标准,这意味着它可以在两者中使用。NET框架和。NET核心。
此方法有两个重载:
需要传入一个类型,这是应该转换的委托类型。需要传入类型和实例。同样,类型是应该转换的委托类型。它们的区别在于,前者创建的委托直接调用实例方法本身,而后者更为原始,实际调用实例对象时需要传入实例对象。
使用上面的StubClass会更直观:
私有类Stubclass { public int Test(int I){ return I;}}前者获取等效于int Test(int i)方法的委托,后者获取等效于int Test(StubClass instance,int i)方法的委托。(在IL中,所有的方法其实都是后者,而前者更像C#中的代码,很容易理解。)
单独使用CreateDelegate方法可能需要尝试每次第一个参数应该传入什么,所以我将其封装到一个通用版本中,以提高易用性。
使用系统;使用系统。Linq使用系统。反思;使用系统。诊断。合同;命名空间Walter LV . demo { public static class instance methodbuilder,treturn value {///summary///叫做like var result=func(t)。////summary[Pure]public static FuncT,treturnnvalue createinstancemotinstancetype(TInstanceType实例,MethodInfo方法){ if (instance==null)抛出新的ArgumentNullException(name of(instance));if (method==null)抛出新的ArgumentNullException(name of(method));return (FuncT,TReturnValue)方法。CreateDelegate(类型为(FuncT,TReturnValue),实例);} ///summary ///被调用为var result=func(this,t)。////summary[Pure]public static functionetype,T,treturnvalcreatemethoditionetype(method info方法){ if (method==null)抛出新的ArgumentNullException(nameof(方法));return (FuncTInstanceType,T,TReturnValue)方法。CreateDelegate(类型为(FuncTInstanceType,T,treturnVaLue));}}}泛型的多参数版本可以使用泛型类型生成器生成。我在“生成代码,自动生成从T到T1、T2和TN ——-吕一的多种类型的泛型”一文中写了一个泛型生成器,可以稍微修改一下,以适应这个泛型类。
摘要
以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。有问题可以留言交流。谢谢你的支持。
版权声明:如何详细说明 NET Core/Framework创建委托来大大提高反射调用的性能是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。