为什么反射在.NET中表现不佳?

时间:2009-07-22 01:32:26

标签: .net performance reflection

我很想知道技术原因:为什么反射在.NET中表现不佳?

7 个答案:

答案 0 :(得分:16)

  

反射效果不佳

这是一个非常负载的声明。 “表现良好”是相对的。与静态代码相比,反射调用不会执行 。但是,几乎在所有情况下,.NET中的反射都非常快。我不能低估这一点。反思在.NET 1.x天以及其他语言中得到了不好的声誉,但.NET 2.0+中的反映非常快

在99%的案例中,“反思太慢”是一个无关紧要的问题。我怀疑你是否需要考虑反射呼叫与静态呼叫的性能影响。

答案 1 :(得分:5)

简单地说“反射”执行缓慢是在很宽的毯子下面融入了很多功能。 .NET中的反思有几个类,每个类都有不同级别的“性能”。首先,使用typeof()运算符实际上是一种反射形式......它查询CLR元数据的类型。但是,typeof()执行速度非常快(在接近空闲时间内。)使用其他类型相关的“反射”,例如is运算符,sizeof()运算符等也几乎是免费的(它们基本上是免费的)表现就像是静态代码。)

用于检索有关类型的信息的反射,虽然比typeof()慢,但考虑到指针遍历和元数据探测的数量,也非常非常快。元数据探测是.NET代码的一种常见做法,特别是在处理自定义属性时。

关于反思的重要性能问题与调用有关。访问类型信息和阅读元数据非常轻松。在涉及动态调用属性,索引器,方法或通过反射动态构造新类型的那一刻,您将获得数量级的性能损失。

然而,反射仍然是进程内执行,因此在您担心稍微动态调用的性能损失之前,请确保没有任何明显更大的性能瓶颈,例如进程间执行,网络调用(即数据库,网络服务等)当谈到性能时,从最大的性能打击开始,然后从那里开始工作。从性能角度来看,反射(包括动态调用)通常是您应该担心的最后一件事。

<强>附录:

稍后想一想,但如果您需要对后期绑定类型成员进行高度动态调用,则应该考虑轻量级代码生成。使用System.Reflection.Emit命名空间,您可以使用DynamicMethod等实用程序在运行时生成可执行早期绑定调用的轻量级代码。缓存此生成的代码可降低生成代码的初始成本,从而使您能够获得具有早期性能的后期绑定调用的好处。

答案 2 :(得分:4)

关于MSDN上的精彩文章:Dodge Common Performance Pitfalls to Craft Speedy Applications。基本上,这是一个迟到和早期绑定的问题。也就是说,可以在编译时决定什么以及必须在运行时决定什么。从那篇文章......

  

迟到的案件是   MethodBase.Invoke,DynamicMethod via   Invoke,Type.InvokeMember和   迟到的委托呼叫(呼叫   代表通过Delegate.DynamicInvoke)。   所有这些方法都附带   显着更负面   性能影响比   早期案件。即使是最好的   例如,它们通常是一个订单   比最慢的幅度慢   早期案件。

他打破了我们对早期和晚期绑定电话的各种方式进行了不少性能测试。非常值得一读。

答案 3 :(得分:2)

反射表现良好,只是 比静态代码更多。

假设您有此代码段:

typeof(SomeClass).GetMethod("SomeStaticMethod").
Invoke(null, new object[] { 1, 2, 3 });

这与此相同:

SomeClass.SomeStaticMethod(1, 2, 3);

但显而易见的是,第一个还有很多工作要做。它必须获取类型信息,遍历它以查看是否存在SomeStaticMethod方法,检查它是什么类型的方法,在实例上调用方法,或者如果它是静态的并且不传递对象数组是参数,装箱/取消装箱整数在这种情况下也是如此。

这可能是一个非常广泛的总结,毫无疑问甚至更多。尽管如此,反射仍然非常快,并且在很多领域都有使用,从WinForms上的数据绑定到ASP.NET MVC中的模型绑定(基于MVC构建的每个对此站点的请求都涉及到一大堆反射,但是,网站速度非常快,MVC被认为是一个非常快速的框架。)

答案 4 :(得分:1)

因为它在运行时涉及字符串查找(类型和成员名称),以及值类型的额外装箱/取消装箱。

答案 5 :(得分:1)

反射涉及转到元数据以将名称解析为标记,然后使用此标记进行查找并检索所需的数据(例如,方法标记用于获取有关方法,参数的信息......等)。

由于两个原因,这个过程很昂贵。 1-很多查询正在进行中。 2-触摸通常不被触摸的页面(冷页面),其中包含元数据表。

直接访问元数据非常昂贵,CLR维护缓存以快速完成此过程并避免在以非反射方式访问事物时触摸元数据表,但是一旦您进行反思,我们会绕过这些缓存并直接转到来源。

答案 6 :(得分:0)

反射确实在.NET中表现良好 - 它的功能。

然而,反射,因为它是已编译类型的运行时分析,需要相当多的开销。一般来说,做静态类型信息的字符串查找,以及遍历类元数据等等都需要一段时间。

这并不是说它真的很慢 - 它只比完全编译的strait方法调用和查找慢很多。它应该是 - 但我真的更想到它,因为在任何系统中,编译代码比动态查找信息更快。