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

时间:2021-07-23 06:55:40

I am interested to know the technical reasons: why does reflection not perform well in .NET?

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

7 个解决方案

#1


Reflection performs well, it just does a lot more than static code.

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

Say you have this code snippet:

假设您有此代码段:

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

This is the same as this:

这与此相同:

SomeClass.SomeStaticMethod(1, 2, 3);

But it should be obvious that the first one has a lot more work to do. It has to get type information, traverse it to see if there's a SomeStaticMethod method, check what kind of method it is, invoke the method on an instance, or not if it's static and pass the object array is parameters, boxing/unboxing the integers in this case as well.

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

And this is probably a very broad summary, there's no doubt even more going on. Yet despite this, reflection is still very fast and used in a lot of areas, from databinding on WinForms to model binding in ASP.NET MVC (every request you make to this site, built on MVC, involves a whole bunch of reflection and yet, the site is very fast and MVC is regarded as a very fast framework).

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

#2


reflection does not perform well

反射效果不佳

That's a very loaded statement. "Perform well" is relative. Compared to static code, reflective calls do not perform quite as well. However, in nearly all cases, reflection in .NET is extremely fast. I cannot understate that enough. Reflection got a bad reputation from .NET 1.x days and perhaps other languages, but reflection in .NET 2.0+ is blisteringly quick.

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

In 99% of cases, the "is reflection too slow" is an irrelevant concern. I doubt you would need to bother measuring the performance impact of a reflective call vs a static one.

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

#3


Simply stating that "Reflection" performs slow is lumping a hell of a lot of functionality underneath a very broad blanket. Reflection in .NET comes in several classes, each with a different level of "performance". For one, use of the typeof() operator is actually a form of reflection...it queries the CLR metadata for a type. However, typeof() executes extremely fast (in near-free time.) Use of other type-related "reflection", such as the is operator, sizeof() operator, etc. are also nearly free (they basically perform as if they were static code.)

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

Reflection used to retrieve information about a type, while slower than typeof(), is also very, very fast considering the amount of pointer traversal and metadata probing that goes on. Metadata probing is a fairly common practice with .NET code, particularly when it comes to working with custom attributes.

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

The big performance concern in regards to reflection has to do with invocation. Accessing type information and reading metadata are pretty light weight. The moment you involve dynamic invocation of properties, indexers, methods, or dynamically construct new types via reflection, you take an orders-of-magnitude performance hit.

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

Reflection is still an in-process execution, however, so before you worry about the performance hit of a little dynamic invocation, make sure that there aren't any significantly larger performance bottlenecks, such as inter-process execution, network calls (i.e. database, web service, etc.) When it comes to performance, start with the biggest performance hit, and work your way down from there. Reflection, including dynamic invocation, is usually one of the last things you should worry about from a performance standpoint.

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

Addendum:

A bit of an after thought, but if you require a high degree of dynamic invocation of late-bound type members, you should look into lightweight code generation. Using the System.Reflection.Emit namespace, you can use utilities such as DynamicMethod to generate lightweight code at runtime that can perform early-bound calls. Caching this generated code reduces the initial cost of generating it, allowing you to gain the benefit of late-bound calls with early-bound performance.

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

#4


Terrific article on that on MSDN: Dodge Common Performance Pitfalls to Craft Speedy Applications. Basically, it's a question of late and early binding. That is, what can be decided at compile-time and what must be decided at runtime. From that article ...

MSDN上关于这一点的精彩文章:避免制作快速应用程序的常见性能陷阱。基本上,这是一个迟到和早期绑定的问题。也就是说,可以在编译时决定什么以及必须在运行时决定什么。从那篇文章......

The late-bound cases are MethodBase.Invoke, DynamicMethod via Invoke, Type.InvokeMember, and late-bound delegate calls (calls on delegates via Delegate.DynamicInvoke). All of these methods come with significantly more negative performance implications than the early-bound cases. Even in the best case, they're typically an order of magnitude slower than the slowest early-bound case.

后期绑定的情况是MethodBase.Invoke,DynamicMethod通过Invoke,Type.InvokeMember和后期绑定委托调用(通过Delegate.DynamicInvoke调用委托)。与早期约束的案例相比,所有这些方法都具有明显更多的负面性能影响。即使在最好的情况下,它们通常比最慢的早期情况慢一个数量级。

He breaks our quite a few performance tests of the various ways of making early and late bound calls. Well worth the read.

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

#5


Because it involves string lookups (of type and member names) at run-time, as well as extra boxing/unboxing for value types.

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

#6


Reflection involves going to the metadata to resolve the names to tokens, it then uses this tokens for lookup and retrieving the data you want ( for example, a method token is used to get the information about the method, parameters ...etc).

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

This process is expensive because of 2 reasons. 1- A lot of lookup is going on. 2- Touching pages that are not usually touched ( cold pages ), which contain the metadata tables.

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

Accessing Metadata directly is expensive, the CLR maintain caches to make this process fast and to avoid touching the metadata tables when you access things in non-reflection way, however once you go to reflection, we bypass these caches and go directly to the source.

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

#7


Reflection does perform well in .NET - for what it does.

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

However, reflection, since it's a runtime analysis of already compiled types, requires quite a bit of overhead. In general, doing things like string lookups of static type information, and walking the class metadata, etc, is going to take a while.

但是,反射,因为它是已编译类型的运行时分析,需要相当多的开销。通常,执行诸如静态类型信息的字符串查找以及遍历类元数据等操作需要一段时间。

That isn't to say that it's really slow - it's just a LOT slower than fully compiled, strait method calls and lookups. It should be - but I really think of it more as compiled code is faster than dynamically looking up information, in any system.

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

#1


Reflection performs well, it just does a lot more than static code.

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

Say you have this code snippet:

假设您有此代码段:

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

This is the same as this:

这与此相同:

SomeClass.SomeStaticMethod(1, 2, 3);

But it should be obvious that the first one has a lot more work to do. It has to get type information, traverse it to see if there's a SomeStaticMethod method, check what kind of method it is, invoke the method on an instance, or not if it's static and pass the object array is parameters, boxing/unboxing the integers in this case as well.

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

And this is probably a very broad summary, there's no doubt even more going on. Yet despite this, reflection is still very fast and used in a lot of areas, from databinding on WinForms to model binding in ASP.NET MVC (every request you make to this site, built on MVC, involves a whole bunch of reflection and yet, the site is very fast and MVC is regarded as a very fast framework).

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

#2


reflection does not perform well

反射效果不佳

That's a very loaded statement. "Perform well" is relative. Compared to static code, reflective calls do not perform quite as well. However, in nearly all cases, reflection in .NET is extremely fast. I cannot understate that enough. Reflection got a bad reputation from .NET 1.x days and perhaps other languages, but reflection in .NET 2.0+ is blisteringly quick.

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

In 99% of cases, the "is reflection too slow" is an irrelevant concern. I doubt you would need to bother measuring the performance impact of a reflective call vs a static one.

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

#3


Simply stating that "Reflection" performs slow is lumping a hell of a lot of functionality underneath a very broad blanket. Reflection in .NET comes in several classes, each with a different level of "performance". For one, use of the typeof() operator is actually a form of reflection...it queries the CLR metadata for a type. However, typeof() executes extremely fast (in near-free time.) Use of other type-related "reflection", such as the is operator, sizeof() operator, etc. are also nearly free (they basically perform as if they were static code.)

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

Reflection used to retrieve information about a type, while slower than typeof(), is also very, very fast considering the amount of pointer traversal and metadata probing that goes on. Metadata probing is a fairly common practice with .NET code, particularly when it comes to working with custom attributes.

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

The big performance concern in regards to reflection has to do with invocation. Accessing type information and reading metadata are pretty light weight. The moment you involve dynamic invocation of properties, indexers, methods, or dynamically construct new types via reflection, you take an orders-of-magnitude performance hit.

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

Reflection is still an in-process execution, however, so before you worry about the performance hit of a little dynamic invocation, make sure that there aren't any significantly larger performance bottlenecks, such as inter-process execution, network calls (i.e. database, web service, etc.) When it comes to performance, start with the biggest performance hit, and work your way down from there. Reflection, including dynamic invocation, is usually one of the last things you should worry about from a performance standpoint.

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

Addendum:

A bit of an after thought, but if you require a high degree of dynamic invocation of late-bound type members, you should look into lightweight code generation. Using the System.Reflection.Emit namespace, you can use utilities such as DynamicMethod to generate lightweight code at runtime that can perform early-bound calls. Caching this generated code reduces the initial cost of generating it, allowing you to gain the benefit of late-bound calls with early-bound performance.

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

#4


Terrific article on that on MSDN: Dodge Common Performance Pitfalls to Craft Speedy Applications. Basically, it's a question of late and early binding. That is, what can be decided at compile-time and what must be decided at runtime. From that article ...

MSDN上关于这一点的精彩文章:避免制作快速应用程序的常见性能陷阱。基本上,这是一个迟到和早期绑定的问题。也就是说,可以在编译时决定什么以及必须在运行时决定什么。从那篇文章......

The late-bound cases are MethodBase.Invoke, DynamicMethod via Invoke, Type.InvokeMember, and late-bound delegate calls (calls on delegates via Delegate.DynamicInvoke). All of these methods come with significantly more negative performance implications than the early-bound cases. Even in the best case, they're typically an order of magnitude slower than the slowest early-bound case.

后期绑定的情况是MethodBase.Invoke,DynamicMethod通过Invoke,Type.InvokeMember和后期绑定委托调用(通过Delegate.DynamicInvoke调用委托)。与早期约束的案例相比,所有这些方法都具有明显更多的负面性能影响。即使在最好的情况下,它们通常比最慢的早期情况慢一个数量级。

He breaks our quite a few performance tests of the various ways of making early and late bound calls. Well worth the read.

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

#5


Because it involves string lookups (of type and member names) at run-time, as well as extra boxing/unboxing for value types.

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

#6


Reflection involves going to the metadata to resolve the names to tokens, it then uses this tokens for lookup and retrieving the data you want ( for example, a method token is used to get the information about the method, parameters ...etc).

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

This process is expensive because of 2 reasons. 1- A lot of lookup is going on. 2- Touching pages that are not usually touched ( cold pages ), which contain the metadata tables.

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

Accessing Metadata directly is expensive, the CLR maintain caches to make this process fast and to avoid touching the metadata tables when you access things in non-reflection way, however once you go to reflection, we bypass these caches and go directly to the source.

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

#7


Reflection does perform well in .NET - for what it does.

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

However, reflection, since it's a runtime analysis of already compiled types, requires quite a bit of overhead. In general, doing things like string lookups of static type information, and walking the class metadata, etc, is going to take a while.

但是,反射,因为它是已编译类型的运行时分析,需要相当多的开销。通常,执行诸如静态类型信息的字符串查找以及遍历类元数据等操作需要一段时间。

That isn't to say that it's really slow - it's just a LOT slower than fully compiled, strait method calls and lookups. It should be - but I really think of it more as compiled code is faster than dynamically looking up information, in any system.

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