c# - ¿Qué tan costoso es el reflejo de.NET?
performance reflection (13)
Al igual que con todas las cosas en la programación, tiene que 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 mapas O / R en C # que usaba la reflexión para hacer los enlaces. Esto funcionó fantásticamente bien. La mayoría del código de reflexión solo se ejecutó una vez, por lo que cualquier impacto de rendimiento fue bastante pequeño, pero los beneficios fueron excelentes. Si escribiera un nuevo algoritmo de ordenamiento aleatorio, probablemente no usaría la reflexión, ya que probablemente se escalaría mal.
Aprecio que no haya respondido exactamente a tu pregunta aquí. Mi punto es que realmente no importa. Use la reflexión cuando sea apropiado. Es solo otra característica del idioma que necesita para aprender cómo y cuándo usarla.
Constantemente escucho lo mala que es usar la reflexión. Aunque generalmente evito la reflexión y rara vez encuentro situaciones en las que es imposible resolver mi problema sin él, me preguntaba ...
Para aquellos que han utilizado la reflexión en las aplicaciones, ¿ha medido los impactos de rendimiento y es realmente tan malo?
Como con todo, se trata de evaluar la situación. En DotNetNuke hay un componente bastante básico llamado FillObject
que usa la reflexión para poblar objetos de datarows.
Este es un escenario bastante común y hay un artículo en MSDN, Uso de la reflexión para vincular Business Objects a ASP.NET Form Controls que cubre los problemas de rendimiento.
Dejando de lado el rendimiento, una cosa que no me gusta de usar la reflexión en ese escenario en particular es que tiende a reducir la capacidad de entender el código de un vistazo rápido que para mí no vale la pena el esfuerzo si consideras que también pierdes compilación seguridad en el tiempo en lugar de conjuntos de datos fuertemente tipados o algo así como LINQ to SQL .
Creo que encontrarás que la respuesta es, depende. No es un gran problema 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.
En su charla El rendimiento de las cosas cotidianas , Jeff Richter muestra que llamar a un método por reflexión es unas 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 asigne un delegado y luego llame al delegado.
La reflexión es costosa debido a las muchas comprobaciones que debe realizar el tiempo de ejecución cada vez que realice 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 ejecutas ese método internamente, hay un código que hace cosas como verificar que pasaste una lista de parámetros compatibles antes de ejecutar el método de destino real.
Si es posible, siempre se recomienda que uno almacene en caché el controlador del método si va a reutilizarlo continuamente en el futuro. Como todos los buenos consejos de programación, a menudo tiene sentido evitar repetirse uno mismo. En este caso, sería inútil buscar continuamente el método con ciertos parámetros y luego ejecutarlo cada vez.
Meter alrededor de la fuente y echar un vistazo a lo que se está haciendo.
La reflexión no ralentiza 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.
La reflexión puede tener un impacto notable en el rendimiento si lo utiliza para la creación frecuente de objetos. He desarrollado una aplicación basada en el Bloque de aplicaciones de interfaz de usuario compuesto que depende en gran medida 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 lo único que necesita es inspeccionar un conjunto, recomendaría Mono.Cecil que es muy ligero y rápido
Mi experiencia más pertinente fue escribir código para comparar cualesquiera dos entidades de datos del mismo tipo en un modelo de objeto grande en cuanto a propiedad. Lo tengo funcionando, lo probé, corrí como un perro, obviamente.
Me sentí abatido, y de la noche a la mañana me di cuenta de que, sin cambiar la lógica, podía usar el mismo algoritmo para generar automáticamente métodos para realizar la comparación, pero accediendo estáticamente a las propiedades. No tomó tiempo en adaptar el código para este propósito y tuve la capacidad de hacer una comparación profunda de las entidades con el código estático que podía actualizarse con solo hacer clic en un botón cada vez que cambiaba 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 generar código automáticamente para compilar en lugar de realizar operaciones de tiempo de ejecución y esto a menudo vale la pena considerarlo.
No masivamente. Nunca he tenido un problema con él en el desarrollo de escritorio a menos que, como dice Martin, lo estés usando en una ubicación tonta. He escuchado que muchas personas tienen temores irracionales sobre su desempeño en el desarrollo de computadoras de escritorio.
Sin embargo, en el Marco Compacto (en el que suelo estar), es bastante anathema y debe evitarse como la plaga en la mayoría de los casos. Todavía puedo usarlo con poca frecuencia, pero tengo que tener mucho cuidado con su aplicación, que es mucho menos divertida. :(
Si no estás en un bucle, no te preocupes por eso.
Ya es bastante malo que tenga que preocuparse incluso por la reflexión realizada internamente por las bibliotecas .NET para el código de rendimiento crítico.
El siguiente ejemplo es obsoleto: verdadero en el momento (2008), pero hace mucho que se corrigió en las versiones más recientes de CLR. 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 el 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 de 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.
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 en el día a día se usa para poblar 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.
He ideado una prueba que creo que es justa, ya que almacena en caché todas las llamadas que se repiten y solo cronometra la llamada real de SetValue o GetValue. Todo el código fuente para la prueba de rendimiento se encuentra en bitbucket en: https://bitbucket.org/grenade/accessortest . El escrutinio es bienvenido y animado.
La conclusión a la que llegué es que no es práctico y no proporciona mejoras notables en el rendimiento para eliminar la reflexión en una capa de acceso a datos que genera menos de 100.000 filas en un momento en que la implementación de la reflexión se realiza correctamente.
El gráfico anterior muestra el resultado de mi pequeño punto de referencia y muestra que los mecanismos que superan la reflexión, 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.
Es. Pero eso depende de lo que estés tratando de hacer.
Uso la reflexión para cargar ensamblajes (complementos) dinámicamente 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ás reflexionando dentro de una serie de bucles anidados con llamadas de reflexión en cada uno, diría que deberías revisar tu 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 usado por .NET, así que no veo por qué no debería intentarlo.