2009-07-22 18 views

Respuesta

2

La reflexión funciona bien, solo hace mucho más que código estático.

Digamos que tiene este fragmento de código:

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

Esto es lo mismo que esto:

SomeClass.SomeStaticMethod(1, 2, 3); 

pero debería ser obvio que el primero tiene mucho más trabajo que hacer. Tiene que obtener información de tipo, recorrerla para ver si hay un método SomeStaticMethod, verificar qué tipo de método es, invocar el método en una instancia, o no, si es estático y pasar la matriz de objetos a parámetros, boxing/unboxing the integers en este caso también.

Y este es probablemente un resumen muy amplio, no hay duda de que aún hay más cosas en marcha. Sin embargo, a pesar de esto, la reflexión es aún muy rápida y se usa en muchas áreas, desde la unión de datos en WinForms hasta el enlace de modelo en ASP.NET MVC (cada solicitud que realice en este sitio, basada en MVC, implica un montón de reflexión y, sin embargo, el sitio es muy rápido y MVC se considera un marco muy rápido).

1

Porque implica búsquedas de cadenas (de tipo y nombres de miembros) en tiempo de ejecución, así como boxeo/desempaquetado adicional para tipos de valores.

4

Excelente artículo sobre eso en MSDN: Dodge Common Performance Pitfalls to Craft Speedy Applications. Básicamente, se trata de una unión tardía y temprana. Es decir, qué se puede decidir en tiempo de compilación y qué se debe decidir en tiempo de ejecución. A partir de ese artículo ...

Los casos están enlazados en tiempo de MethodBase.Invoke, DynamicMethod través invocación, Type.InvokeMember y llamadas delegado de enlace en tiempo (llamadas en delegados a través de Delegate.DynamicInvoke). Todos estos métodos vienen con implicaciones de rendimiento significativamente más negativas que casos de vinculación anticipada. Incluso en el mejor caso , por lo general son un orden de magnitud más lenta que el caso más temprano .

Él rompe nuestras bastantes pruebas de rendimiento de las diversas formas de realizar llamadas con límite temprano y tarde. Bien vale la pena leer.

1

La reflexión implica ir a los metadatos para resolver los nombres en tokens, luego usa estos tokens para buscar y recuperar los datos que desea (por ejemplo, un token de método se usa para obtener la información sobre el método, los parámetros ... .etc).

Este proceso es caro debido a 2 razones. 1- Se está realizando una gran cantidad de búsquedas. 2- Tocando páginas que normalmente no se tocan (páginas frías), que contienen las tablas de metadatos.

Acceder directamente a los metadatos es costoso, el CLR mantiene cachés para hacer este proceso rápido y evitar tocar las tablas de metadatos cuando se accede a cosas sin reflexión, sin embargo, una vez que se reflexiona, omitimos estos caches y vamos directamente a la fuente

16

reflexión no funciona bien

Esa es una declaración muy cargado. "Realizar bien" es relativo. En comparación con el código estático, las llamadas reflexivas tampoco realizan . Sin embargo, en casi todos los casos, la reflexión en .NET es extremadamente rápida. No puedo subestimar eso lo suficiente. Reflection obtuvo una mala reputación de .NET 1.x días y tal vez de otros idiomas, pero la reflexión en .NET 2.0+ es increíblemente rápido.

En el 99% de los casos, el "es un reflejo demasiado lento" es una preocupación irrelevante. Dudo que necesites molestarte en medir el impacto en el rendimiento de una llamada reflexiva versus una estática.

+0

Bueno usé la reflexión en una aplicación de formularios de Windows para crear una interfaz de usuario dinámica y no vi ningún problema de rendimiento. Por supuesto, puede ser diferente en una aplicación "performant critical" que no sé. – Malcolm

0

La reflexión funciona bien en .NET, por lo que hace.

Sin embargo, la reflexión, ya que es un análisis del tiempo de ejecución de los tipos ya compilados, requiere bastante sobrecarga. En general, hacer cosas como búsquedas de cadenas de información de tipo estático y recorrer los metadatos de la clase, etc., llevará un tiempo.

Eso no quiere decir que sea realmente lento, es mucho más lento que las llamadas y búsquedas de método de estrecho compilado. Debería serlo, pero realmente lo pienso más, ya que el código compilado es más rápido que la búsqueda dinámica de información en cualquier sistema.

5

Simplemente diciendo que "Reflection" funciona con lentitud está acumulando muchísima funcionalidad debajo de una manta muy amplia. La reflexión en .NET viene en varias clases, cada una con un nivel diferente de "rendimiento". Por un lado, el uso del operador typeof() es en realidad una forma de reflexión ... consulta los metadatos CLR para un tipo. Sin embargo, typeof() ejecuta extremadamente rápido (en tiempo casi libre). El uso de otro "reflejo" relacionado con el tipo, como el operador is, sizeof() operador, etc. también son casi gratuitos (básicamente funcionan como si fueran código estático.)

La reflexión utilizada para recuperar información acerca de un tipo, aunque es más lenta que typeof(), también es muy, muy rápida teniendo en cuenta la cantidad de exploración de puntero y sondeos de metadatos que se realizan. La prueba de metadatos es una práctica bastante común con el código .NET, especialmente cuando se trata de trabajar con atributos personalizados.

La gran preocupación de rendimiento en lo que respecta a la reflexión tiene que ver con la invocación. Acceder a la información de tipo y leer los metadatos es muy ligero. En el momento en que involucras la invocación dinámica de propiedades, indizadores, métodos o construyes dinámicamente nuevos tipos a través de la reflexión, tomas un golpe de rendimiento de órdenes de magnitud.

La reflexión sigue siendo una ejecución en proceso, sin embargo, antes de preocuparse por el rendimiento de una pequeña invocación dinámica, asegúrese de que no haya cuellos de botella de rendimiento significativamente mayores, como la ejecución entre procesos, la red llamadas (es decir, base de datos, servicio web, etc.) Cuando se trata de rendimiento, comience con el mayor rendimiento y avance desde allí. La reflexión, incluida la invocación dinámica, suele ser una de las últimas cosas de las que debe preocuparse desde el punto de vista del rendimiento.

Adición:

Un poco de después de pensamiento, pero si requiere un alto grado de invocación dinámica de los miembros de tipo de enlace en tiempo, usted debe buscar en la generación de código ligero. Utilizando el espacio de nombres System.Reflection.Emit, puede usar utilidades como DynamicMethod para generar código liviano en tiempo de ejecución que pueda realizar llamadas de enlace temprano. El almacenamiento en caché de este código generado reduce el costo inicial de generarlo, lo que le permite obtener el beneficio de las llamadas con límite de entrega con el rendimiento de enlace anticipado.

Cuestiones relacionadas