type - using generic parameters c#
¿Los genéricos C#tienen un beneficio de rendimiento? (12)
Tengo varias clases de datos que representan varias entidades.
¿Qué es mejor: escribir una clase genérica (por ejemplo, imprimir o imprimir XML) usando genéricos e interfaces, o escribir una clase separada para tratar con cada clase de datos?
¿Hay algún beneficio de rendimiento o algún otro beneficio (aparte de ahorrarme el tiempo de escribir clases por separado)?
¡Los genéricos son más rápidos!
También descubrí que Tony Northrup escribió cosas equivocadas sobre el desempeño de los genéricos y los no genéricos en su libro.
Escribí sobre esto en mi blog: http://andriybuday.blogspot.com/2010/01/generics-performance-vs-non-generics.html
Aquí hay un gran artículo donde el autor compara el desempeño de los genéricos y no genéricos:
nayyeri.net/use-generics-to-improve-performance
El uso de medicamentos genéricos tiene un beneficio significativo en el rendimiento: eliminas el boxeo y el desempaquetado . En comparación con el desarrollo de sus propias clases, es un lanzamiento de moneda (con un lado de la moneda ponderado más que el otro). Tira el tuyo solo si crees que puedes superar a los autores del marco.
En el caso de colecciones genéricas frente a boxing et al, con colecciones más antiguas como ArrayList, los genéricos son una ganancia de rendimiento. Pero en la gran mayoría de los casos, este no es el beneficio más importante de los genéricos. Creo que hay dos cosas que son de mucho mayor beneficio:
- Escriba seguridad.
- Auto documentación también conocida como más legible.
Los genéricos promueven la seguridad de tipo, forzando una colección más homogénea. Imagine tropezar con una cadena cuando espera una int. Ay.
Las colecciones genéricas también son más auto documentadas. Considere las dos colecciones a continuación:
ArrayList listOfNames = new ArrayList();
List<NameType> listOfNames = new List<NameType>();
Al leer la primera línea, puede pensar que listOfNames es una lista de cadenas. ¡Incorrecto! En realidad, está almacenando objetos de tipo NameType. El segundo ejemplo no solo exige que el tipo debe ser NameType (o un descendiente), sino que el código es más legible. Sé de inmediato que necesito encontrar TypeName y aprender a usarlo simplemente mirando el código.
He visto muchas de estas preguntas "no funciona x mejor que y" en . La pregunta aquí fue muy justa, y resulta que los genéricos son una ganancia de cualquier forma que despellejes al gato. Pero al final del día, el punto es proporcionar al usuario algo útil. Claro, su aplicación debe poder funcionar, pero también no debe fallar, y debe ser capaz de responder rápidamente a los errores y solicitudes de funciones. Creo que puede ver cómo estos dos últimos puntos se relacionan con la seguridad del tipo y la legibilidad del código de las colecciones genéricas. Si fuera el caso opuesto, si ArrayList superaba a List <>, probablemente aún tomaría la implementación List <> a menos que la diferencia de rendimiento fuera significativa.
En lo que respecta al rendimiento (en general), estoy dispuesto a apostar que encontrará la mayoría de los cuellos de botella en estas áreas en el transcurso de su carrera:
- Diseño deficiente de consultas de bases de datos o bases de datos (incluyendo indexación, etc.)
- Mala gestión de la memoria (olvidarse de llamar a deshacerse, pilas profundas, aferrarse a objetos demasiado largos, etc.),
- Gestión incorrecta de subprocesos (demasiados subprocesos, sin llamar a IO en una cadena de fondo en aplicaciones de escritorio, etc.),
- Pobre diseño de IO.
Ninguno de estos se soluciona con soluciones de una sola línea. Nosotros, como programadores, ingenieros y geeks, queremos saber todos los pequeños y divertidos trucos de rendimiento. Pero es importante que mantengamos nuestros ojos en la pelota. Creo que centrarme en las buenas prácticas de diseño y programación en las cuatro áreas que mencioné anteriormente hará que eso cause mucho más que preocuparse por las pequeñas ganancias de rendimiento.
Hice algunos benchmarking simples en ArrayList vs Generic Lists para una pregunta diferente: Generics vs. Array Lists , su kilometraje variará, pero la Lista genérica fue 4.7 veces más rápida que ArrayList.
Así que sí, el boxeo / unboxing es crítico si estás haciendo muchas operaciones. Si estás haciendo cosas sencillas de CRUD, no me preocuparía.
Los genéricos en C # son verdaderamente genéricos desde la perspectiva de CLR. No debería haber ninguna diferencia fundamental entre el rendimiento de una clase genérica y una clase específica que hace exactamente lo mismo. Esto es diferente de los genéricos de Java, que son más un molde de tipo automatizado donde sea necesario o plantillas de C ++ que se expanden en tiempo de compilación.
Aquí hay un buen documento, algo antiguo, que explica el diseño básico: "Diseño e implementación de genéricos para .NET Common Language Runtime" .
Si escribe clases a mano para tareas específicas, es probable que pueda optimizar algunos aspectos en los que necesitaría desvíos adicionales a través de una interfaz de tipo genérico.
En resumen, puede haber un beneficio en el rendimiento, pero recomendaría primero la solución genérica y luego la optimizaría si fuera necesario. Esto es especialmente cierto si espera crear una instancia del genérico con muchos tipos diferentes.
Los genéricos son una de las maneras de parametrizar el código y evitar la repetición. Mirando la descripción de su programa y su idea de escribir una clase por separado para tratar con cada objeto de datos, me inclinaría por los genéricos. Tener una sola clase que se ocupe de muchos objetos de datos, en lugar de muchas clases que hacen lo mismo, aumenta su rendimiento. Y, por supuesto, su rendimiento, medido en la capacidad de cambiar su código, suele ser más importante que el rendimiento de la computadora. :-)
No solo puede eliminar el boxeo, sino que las implementaciones genéricas son algo más rápidas que las contrapartes no genéricas con tipos de referencia debido a un cambio en la implementación subyacente.
Los originales fueron diseñados con un modelo de extensión particular en mente. Este modelo nunca se usó realmente (y de todos modos hubiera sido una mala idea), pero la decisión de diseño obligó a un par de métodos a ser virtuales y, por lo tanto, ineficaces (en base a las optimizaciones JIT actuales y anteriores a este respecto).
Esta decisión se corrigió en las clases más nuevas, pero no se puede modificar en las más antiguas sin que sea un posible cambio de rotura binaria.
Además, la iteración a través de foreach en una Lista <> (en lugar de IList <>) es más rápida debido a que el Enumerador de ArrayList requiere una asignación de pila. Es cierto que esto condujo a un error oscuro
No solo sí, sino HECK SÍ. No creía cuán grande de la diferencia podían hacer. Hicimos pruebas en VistaDB después de una reescritura de un pequeño porcentaje de código central que utilizaba ArrayLists y HashTables en los genéricos. 250% o más fue la mejora de velocidad.
Lea mi blog sobre las pruebas que hicimos en genéricos versus colecciones de tipos débiles. Los resultados volaron nuestra mente.
Empecé a reescribir muchos códigos antiguos que usaban las colecciones débilmente tipadas en las fuertemente tipadas. Uno de mis mayores apretones con la interfaz ADO.NET es que no exponen formas más fuertemente tipadas de entrada y salida de datos. El tiempo de lanzamiento desde un objeto y la espalda es un asesino absoluto en aplicaciones de alto volumen.
Otro efecto secundario de escribir fuertemente es que a menudo encontrará problemas de referencia débilmente tipados en su código. Descubrimos que mediante la implementación de estructuras en algunos casos para evitar presionar al GC, podríamos acelerar aún más nuestro código. Combine esto con tipeo fuerte para su mejor aumento de velocidad.
En ocasiones, debe utilizar interfaces de tipo débil en el tiempo de ejecución de punto neto. Siempre que sea posible, busque maneras de permanecer fuertemente tipado. Realmente hace una gran diferencia en el rendimiento para aplicaciones no triviales.
Según Microsoft, los genéricos son más rápidos que el casting (primitivas de boxeo / desempaquetado), lo cual es cierto . También afirman que los genéricos proporcionan un mejor rendimiento que la fusión entre los tipos de referencia, lo que parece ser falso (nadie puede demostrarlo).
Tony Northrup, coautor de MCTS 70-536: Application Development Foundation, afirma en el mismo libro lo siguiente:
No he podido reproducir los beneficios de rendimiento de los genéricos; sin embargo, de acuerdo con Microsoft, los genéricos son más rápidos que el uso del casting. En la práctica, el casting resultó ser varias veces más rápido que usar un genérico. Sin embargo, probablemente no notará las diferencias de rendimiento en sus aplicaciones. (Mis pruebas de más de 100.000 iteraciones tomaron solo unos segundos). Por lo tanto, debería seguir usando los genéricos porque son seguros para el tipo de letra.
No he podido reproducir estos beneficios de rendimiento con genéricos en comparación con el envío entre los tipos de referencia, por lo que diría que la ganancia de rendimiento se "supone" más que "significativa".
Si compara una lista genérica (por ejemplo) con una lista específica para el tipo que utiliza, entonces la diferencia es mínima, los resultados del compilador JIT son casi los mismos.
Si compara una lista genérica con una lista de objetos, la lista genérica tiene importantes ventajas: no hay boxeo / unboxing para los tipos de valor y ningún tipo de verificación para los tipos de referencia.
también las clases de colecciones genéricas en la biblioteca .net se optimizaron en gran medida y es poco probable que lo haga mejor.
Si está pensando en una clase genérica que invoca métodos en alguna interfaz para hacer su trabajo, será más lenta que las clases específicas que utilizan tipos conocidos, porque llamar a un método de interfaz es más lento que una llamada de función (no virtual).
Por supuesto, a menos que el código sea la parte lenta de un proceso de rendimiento crítico, debe enfocarse en la claridad.
Ver el blog de Rico Mariani en MSDN también:
http://blogs.msdn.com/ricom/archive/2005/08/26/456879.aspx
Q1: ¿Cuál es más rápido?
La versión de Generics es considerablemente más rápida, ver abajo.
El artículo es un poco viejo, pero da los detalles.