¿Qué tan costoso es el reflejo .NET?

210

Constantemente escucho lo mal que es usar la reflexión. Si bien generalmente evito la reflexión y rara vez encuentro situaciones en las que es imposible resolver mi problema sin ella, me preguntaba ...

Para aquellos que han usado la reflexión en aplicaciones, ¿han medido los éxitos de rendimiento y, realmente, es tan malo?

Dan Herbert
fuente
También es posible que desee consultar esta pregunta. stackoverflow.com/questions/224232/…
smaclell
1
Use la API en fasterflect.codeplex.com. Acelerará la reflexión como 500x para captadores / setters / invocadores y algunas otras cosas. La fuente y la información sobre cómo funciona también está allí si necesita ampliarla.
Brandon Moore
3
¿Cómo se verifica esta información en 2014? ¿Ha cambiado algo en estos 4 años?
Arnthor
1
La tarea simple de asignar un valor a una propiedad de instancia es aproximadamente 150 veces más lenta al hacerlo con reflexión (PropertyInfo.SetValue (instancia, valor)) que con una codificación directa (instancia.propiedad = valor) Esto está en .NET 4.0
Thanasis Ioannidis

Respuestas:

130

Es. Pero eso depende de lo que intentes hacer.

Utilizo la reflexión para cargar dinámicamente ensamblajes (complementos) y su "penalización" de rendimiento no es un problema, ya que la operación es algo que hago durante el inicio de la aplicación.

Sin embargo, si está reflejando dentro de una serie de bucles anidados con llamadas de reflexión en cada uno, le diría que debería volver a visitar su código :)

Para operaciones de "un par de veces", la reflexión es perfectamente aceptable y no notará ningún retraso o problema con ella. Es un mecanismo muy poderoso e incluso es utilizado por .NET, así que no veo por qué no deberías intentarlo.

Martin Marconcini
fuente
He estado usando la reflexión para obtener el método, el nombre de clase del método actual para registrar el error en try-catch. básicamente para evitar codificar el nombre de la función mientras se registra el error. ¿Debo preocuparme?
Sangram Nandkhile
@Sangram no, eso está bien
Karthik AMR
@Sangram no, a menos que tenga muchos errores que requieran una captura constante, lo que debería ser un problema diferente :)
Martin Marconcini
55
@Sangram, aunque el rendimiento de la reflexión no debería ser el problema en su caso, parece que está tratando de volver a implementar lo que las antiguas excepciones proporcionan de una manera mucho más elegante fuera de la caja ...
Jacek Gorgoń
152

En su charla The Performance of Everyday Things , Jeff Richter muestra que llamar a un método por reflexión es aproximadamente 1000 veces más lento que llamarlo normalmente.

Consejo de Jeff: si necesita llamar al método varias veces, use la reflexión una vez para encontrarlo, luego asígnelo a un delegado y luego llame al delegado.

ESRogs
fuente
18
También asistí a Devscovery y estoy de acuerdo con estos resultados para .NET 3.5. ¡Volver a compilar el programa de referencia de rendimiento Devscovery para .NET 4 muestra una mejora masiva! El costo se reduce a 100 veces más lento. El uso de la reflexión para las búsquedas typeof () no cambia entre .NET 3.5 y .NET 4.
John Wigger
61

El rendimiento de la reflexión dependerá de la implementación (las llamadas repetitivas deben almacenarse en caché, por ejemplo:) entity.GetType().GetProperty("PropName"). Como la mayor parte de la reflexión que veo a diario se usa para llenar entidades de lectores de datos u otras estructuras de tipo de repositorio, decidí comparar el rendimiento específicamente en la reflexión cuando se usa para obtener o establecer propiedades de un objeto.

Diseñé una prueba que creo que es justa, ya que almacena en caché todas las llamadas repetidas y solo veces la llamada real de SetValue o GetValue. Todo el código fuente para la prueba de rendimiento está en bitbucket en: https://bitbucket.org/grenade/accessortest . El escrutinio es bienvenido y alentado.

La conclusión a la que he llegado es que no es práctico y no proporciona mejoras de rendimiento notables para eliminar la reflexión en una capa de acceso a datos que devuelve menos de 100,000 filas en un momento en que la implementación de la reflexión se realiza correctamente.

Gráfico del tiempo (y) contra el número de entidades pobladas (x)

El gráfico anterior muestra el resultado de mi pequeño punto de referencia y muestra que los mecanismos que superan el reflejo, solo lo hacen notablemente después de la marca de 100,000 ciclos. La mayoría de los DAL solo devuelven varios cientos o quizás miles de filas a la vez y en estos niveles la reflexión funciona bien.

granada
fuente
9
No necesariamente. Sus conversiones DAL pueden ser solo en unos pocos miles de elementos, pero multiplíquelo por usuarios concurrentes que usen su aplicación (si es web) y puede sumar como si convirtiera millones de elementos. Si un método particular es 100 veces más lento, será mucho más lento en conjuntos pequeños y grandes. Más lento es más lento.
Robert Koritnik
@RobertKoritnik Eso supone que los métodos web en su servidor no son asíncronos
Kurren
La asincronía de @kurren no afecta la reflexión sino más bien los recursos del servidor. Los métodos web asíncronos, por supuesto, podrán servir a más usuarios, pero la reflexión seguirá siendo lenta. Y la reflexión en sí misma AFAIK es un proceso sincrónico de todos modos. La obtención de datos, por otro lado, será la única parte que jugará muy bien con un diseño asincrónico.
Robert Koritnik
3
¿Cuál es el método Hyper en el gráfico? ¿En qué se diferencia de Reflector?
Bryan Legend
Debería haber hecho referencia a este @LoneCoder: codeproject.com/Articles/18450/… por stackoverflow.com/users/23354/marc-gravell
granada
14

Si no estás en un bucle, no te preocupes por eso.

David Plumpton
fuente
12

Mi experiencia más pertinente fue escribir código para comparar dos entidades de datos del mismo tipo en un modelo de objeto grande en cuanto a propiedades. Lo hice funcionar, lo intenté, corrí como un perro, obviamente.

Estaba abatido, y de la noche a la mañana me di cuenta de que sin cambiar la lógica, podría usar el mismo algoritmo para generar automáticamente métodos para hacer la comparación pero acceder estáticamente a las propiedades. No me llevó mucho tiempo adaptar el código para este propósito y tuve la capacidad de hacer una comparación profunda de las propiedades con entidades con código estático que podría actualizarse con solo hacer clic en un botón cada vez que cambiara el modelo de objetos.

Mi punto es: en conversaciones con colegas, ya que he señalado varias veces que su uso de la reflexión podría ser autogenerar código para compilar en lugar de realizar operaciones de tiempo de ejecución y esto a menudo vale la pena considerarlo.

Gaz
fuente
Teniendo en cuenta que Visual Studio tiene un excelente soporte de plantillas, es una forma práctica de usar la generación de código
Sebastian
12

No masivamente Nunca he tenido un problema con él en el desarrollo de escritorio a menos que, como dice Martin, lo esté usando en una ubicación tonta. He oído que mucha gente tiene miedos completamente irracionales sobre su desempeño en el desarrollo de escritorio.

Sin embargo, en el Marco Compacto (en el que generalmente estoy), es prácticamente anatema y debe evitarse como la peste en la mayoría de los casos. Todavía puedo evitar usarlo con poca frecuencia, pero tengo que tener mucho cuidado con su aplicación, que es mucho menos divertida. :(

Molesto
fuente
55
+1 por enseñarme una nueva palabra: anatema. También por mencionar miedos irracionales. Temo a los programadores que temen irracionalmente: muestra que realmente no saben lo que están haciendo y simplemente basan lo que hacen en lo que otras personas les dicen. tos carga de culto tos
bsneeze
1
Ahhhh Cargo Cult. Ahora hay un buen ejemplo de comportamiento humano curioso.
Triste
10

Ya es bastante malo que tenga que preocuparse incluso por la reflexión realizada internamente por las bibliotecas .NET para el código crítico de rendimiento.

El siguiente ejemplo es obsoleto, cierto en ese momento (2008), pero hace mucho tiempo corregido en versiones CLR más recientes. Sin embargo, la reflexión en general sigue siendo algo costoso.

Caso en cuestión: nunca debe usar un miembro declarado como "Objeto" en una declaración de bloqueo (C #) / SyncLock (VB.NET) en código de alto rendimiento. ¿Por qué? Debido a que el CLR no puede bloquear un tipo de valor, lo que significa que tiene que hacer una verificación del tipo de reflexión en tiempo de ejecución para ver si su objeto es realmente un tipo de valor en lugar de un tipo de referencia.

McKenzieG1
fuente
13
Para ser justos, una verificación de tipo de reflexión es rápida.
Jimmy
1
Para tal 'código crítico de rendimiento', ¿debería realmente estar usando .NET para empezar?
Seph
1
@Seph: porciones dinámicas / de reflexión de .NET, no. Pero habitual C # /. NET, ¿por qué no? Las aceleraciones de C ++ frente a C # son marginales en la capa de aplicación (C ++ sigue siendo un% más rápido en rutinas matemáticas intensivas). Y supongo que no estás sugiriendo ensamblaje ...
DeepSpace101
Se puede bloquear un tipo de valor en caja (es decir, objeto). @BryceWagner es correcto.
Aves el
1
Para ser justos (para mí), es más exacto decir que la respuesta es "obsoleta", en lugar de "sin sentido". Mis comentarios sobre el comportamiento del bloqueo (obj) Eran precisos en el momento en que se escribieron, pero ese comportamiento específico de la implementación del CLR ya no existe.
McKenzieG1
5

Como con todas las cosas en la programación, debe equilibrar el costo de rendimiento con cualquier beneficio obtenido. La reflexión es una herramienta invaluable cuando se usa con cuidado. Creé una biblioteca de mapeo O / R en C # que usaba la reflexión para hacer los enlaces. Esto funcionó fantásticamente bien. La mayor parte del código de reflexión solo se ejecutó una vez, por lo que cualquier impacto en el rendimiento fue bastante pequeño, pero los beneficios fueron excelentes. Si estuviera escribiendo un nuevo algoritmo de clasificación enredado, probablemente no usaría la reflexión, ya que probablemente escalaría mal.

Aprecio que no haya respondido exactamente su pregunta aquí. Mi punto es que realmente no importa. Use la reflexión donde sea apropiado. Es solo otra característica del idioma que necesita para aprender cómo y cuándo usarla.

Mike Thompson
fuente
3

La reflexión puede tener un impacto notable en el rendimiento si la usa para la creación frecuente de objetos. Desarrollé una aplicación basada en el Bloque de aplicaciones de IU compuesto, que depende mucho de la reflexión. Hubo una notable degradación del rendimiento relacionada con la creación de objetos a través de la reflexión.

Sin embargo, en la mayoría de los casos no hay problemas con el uso de la reflexión. Si su única necesidad es inspeccionar algún conjunto, le recomendaría Mono.Cecil, que es muy ligero y rápido.

aku
fuente
3

La reflexión es costosa debido a las muchas comprobaciones que debe hacer el tiempo de ejecución cada vez que realiza una solicitud de un método que coincida con una lista de parámetros. En algún lugar profundo, existe un código que recorre todos los métodos para un tipo, verifica su visibilidad, verifica el tipo de retorno y también verifica el tipo de cada parámetro. Todo esto cuesta tiempo.

Cuando ejecuta ese método internamente, hay algún código que hace cosas como verificar que haya pasado una lista compatible de parámetros antes de ejecutar el método de destino real.

Si es posible, siempre se recomienda que se almacene en caché el identificador de método si se va a reutilizar continuamente en el futuro. Como todos los buenos consejos de programación, a menudo tiene sentido evitar repetirse. En este caso, sería un desperdicio buscar continuamente el método con ciertos parámetros y luego ejecutarlo cada vez.

Examine la fuente y eche un vistazo a lo que se está haciendo.

mP.
fuente
3

Como con todo, se trata de evaluar la situación. En DotNetNuke hay un componente bastante básico llamado FillObjectque usa la reflexión para poblar objetos desde datarows.

Este es un escenario bastante común y hay un artículo sobre MSDN, Uso de Reflection para vincular Business Objects a ASP.NET Form Controls que cubre los problemas de rendimiento.

Rendimiento aparte, una cosa que no me gusta de usar la reflexión en ese escenario particular es que tiende a reducir la capacidad de entender el código de un vistazo rápido, lo que para mí no parece que valga la pena cuando consideras que también pierdes compilación seguridad de tiempo en lugar de conjuntos de datos fuertemente tipados o algo así como LINQ to SQL .

lomaxx
fuente
2

Reflection no reduce drásticamente el rendimiento de su aplicación. Es posible que pueda hacer ciertas cosas más rápido al no usar la reflexión, pero si la reflexión es la forma más fácil de lograr alguna funcionalidad, entonces úsela. Siempre puede refactorizar su código lejos de Reflection si se convierte en un problema de rendimiento.

Chris Pietschmann
fuente
1

Creo que encontrará que la respuesta es, depende. No es gran cosa si quieres ponerlo en tu aplicación de lista de tareas. Es un gran problema si quieres ponerlo en la biblioteca de persistencia de Facebook.

tsimon
fuente