Microsoft MVP

Email y Rss

email rss

Klout

Seguidores en facebook

Timeline de mi Twitter

Tienes preguntas?

Ideas de un Conejo
Más allá de los sistemas de información: (C#)=> videojuegos, soluciones a problemas interesantes y Sistemas Operativos
XNA
C#
Eventos
Sistemas Operativos
Review
Varios
PL/SQL
Acerca de

Optimización de Código – Utilizando Generics – C#

April 19th, 2010 by JuanK

TweetFollow @JuanKRuiz

Share

Habitualmente en el proceso de desarrollo de nuestros procesos de desarrollo de software hacemos uso de lo comúnmente llamado Colecciones, es decir arreglos de diferente para solucionar determinados problemas.

Normalmente esto no representa mayor problema hasta que nos encontramos con entornos reales de trabajo, aplicaciones cliente servidor o paginas web accesadas de manera simultanea por decenas o miles de usuarios, o como caso mas crítico un videojuego donde uno o dos usuarios (o a veces decenas o miles de ellos…)realizan millones de operaciones por segundo en nuestros procesadores gráficos y CPU’s.

Las colecciones en estos casos se empiezan a volver un problema, porque?. Bien habitualmente muchos de los elementos que utilizamos en el desarrollo son tipos valor como por ejemplo long (Int64), int (Int32), float(Single), double (Double), estructuras (struct) o enumeraciones (enum) los cuales utilizamos ampliamente con el fin de agilizar el rendimiento de nuestra aplicación, pero lastimosamente en el proceso de incluir estos tipos de dato en una colección estos son encajonados (en adelante se hablará boxing) en un tipo object; Esto se debe a que las colecciones para poder almacenar cualquier valor dentro de si almacenan tipos object.

Gracias a Dios o en lo que sea que crean uds.) el CLR 2.0(conocido por la mayoría como .net Framework 2.0) soporta el uso de Generics los cuales no son mas que una cualidad que permite la implementación de código sin tener totalmente definido el/los tipo(s) de dato que esos metodos usan… pero bueno la idea de este hilo no es hacer un curso de generics, así que en resumen gracias a los generics existen un conjunto de colecciones genericas que se traducen en colecciones a las cuales se les puede indicar que tipo de dato almacenaran (entre otras cosas) lo cual se convierte en la eliminación del proceso de boxing y unboxing para poder manipularlas.

Como acotación adicional los desarrolladores de C++ conocen los generics de la STL (Standard Template Library) por lo cual no suelen llamarlos generics sino templates.

Utilizar generics SI es mucho más rápido

Bien, se preguntaran el porque del titulo… así que antes de entrar en materia les contare…

En varios textos de programación en C# y java los autores suelen utilizar unos recuadros con casos reales o notas al margen, y aunque no se el numero exacto si se que ya son varias veces que he visto mencionar que en la practica las colecciones que usan generics no se muestran mucho mas rápidos que las que utilizan el un/boxing tradicional… lo cual es mentira y me pregunto… en que proyectos han trabajado ellos? tal ves en proyecos web y seguramente no en los grandes proyectos web… lo que sin lugar a dudas es cierto es que un desarrollador que tenga experiencia en el montaje de grandes portales, de aplicaciones cliente servidor con gran numero de usuarios o programadores de videojuego o de aplicaciones científicas los desmentirían por completo. Y este post es para eso para desmentir esa falsa creencia y mostrar la realidad: Las colecciones genericas son mucho más eficientes que las no genéricas.

Demostración

Lo primero que haremos sera crear una pequeña aplicación por consola en C# en la cual declararemos esta constante y la siguiente función:

private static long Boxing_Unboxing()
{
    long suma = 0;
    ArrayList arrayEnteros = new ArrayList();

    for (int i = 0; i < tamano; i++)
        arrayEnteros.Add(i);

    for (int i = 0; i < tamano; i++)
        suma = suma + (int)arrayEnteros[i];

    return suma;
}

No requiere mucha explicación, esta función efectúa el llenado (boxing) de una colección con un numero determinado de elementos y seguidamente suma todos estos elementos en un acumulado (ahí hace unboxing) el cual retorna.

Ahora adicionaremos esta función que hace exactamente lo mismo pero utilizando colecciones genericas:

private static long Generics()
{
    long suma = 0;
    List<int> arrayEnteros = new List</int><int>();

    for (int i = 0; i &lt; tamano; i++)
        arrayEnteros.Add(i);

    for (int i = 0; i &lt; tamano; i++)
        suma = suma + arrayEnteros[i];

    return suma;
}

Ahora en el método main crearemos el código necesario para invocar las dos funciones anteriores, adicionalmente mediremos el tiempo de ejecución de las mismas para lo cual utilizaremos System.Environment.TickCount y finalmente incluiremos código para medir el consumo de memoria de la aplicación para lo cual haremos uso de dos metodos de la clase estática GC, GC.GetTotalMemory para saber el consumo total de memoria en un momento dado y GC.Collect para liberar los recursos que ya no estan en uso. El código queda así:

const int  tamano = 30000000;
static void Main(string[] args)
{
    int tiempo =0;

    tiempo = System.Environment.TickCount;
    long suma = Boxing_Unboxing();
    tiempo = System.Environment.TickCount - tiempo;
    Console.WriteLine(&quot;Resultado: &quot;+suma.ToString()+&quot; Tiempo Un/Boxingt:&quot;+tiempo.ToString().PadLeft(10,' ')
                    + &quot; Memoria: &quot;+GC.GetTotalMemory(false).ToString().PadLeft(7,' '));

    GC.Collect();

    tiempo = System.Environment.TickCount;
    suma = Generics();
    tiempo = System.Environment.TickCount - tiempo;
    Console.WriteLine(&quot;Resultado: &quot; + suma.ToString() + &quot; Tiempo Genericst:&quot; +tiempo.ToString().PadLeft(10, ' ')
                     +&quot; Memoria: &quot; + GC.GetTotalMemory(false).ToString().PadLeft(7, ' '));
    GC.Collect();
    Console.ReadLine();
}

Una vez ejecutado obtendremos los siguientes valores (o muy parecidos dependiendo del computador de cada cual):

Resultado: 199999990000000 Tiempo Un/Boxing : 4695 Memoria: 883595136
Resultado: 199999990000000 Tiempo Generics  :  764 Memoria: 202279736

Como ven en los resultados, generics se muestran aproximadamente 6 veces más rápido que la técnica tradicional y fue casi 5 veces mas efectivo en el uso de la memoria.

Como desconozco que hardware tienen ustedes, pueden hacer pruebas modificando el valor de la constante tamano de acuerdo alas características de su procesador y memoria, esto porque si exceden el limite de almacenamiento en memoria de sus máquinas el sistema operativo iniciara el proceso de swap a disco poniendose la cosa muuuy lenta… ahí obtendrán diferencias de tiempo mucho mayores incluso proporcionalmente.

Hasta la próxima.

Print Friendly
Share

TweetFollow @JuanKRuiz

  • 9 Comentarios »
  • Publicado en la categoría 'C#'

9 comentarios to “Optimización de Código – Utilizando Generics – C# ”


  • tavox Says:
    January 21st, 2008 at 10:06 am  

    Me gusta tu sitio, manejas cosas muy interesantes

    saludox

  • expilu Says:
    January 30th, 2008 at 5:57 am  

    Buenas, tenía una duda con respecto a esto…
    ¿Y no sería todavía mejor un array de toda la vida?
    He hecho mi propia prueba añadiendo esta función a su código (y en el main el conteo de tiempo y memoria como usted lo hizo en los otros dos casos):

    private static long arraydetoalavida()
    {
    long suma = 0;
    int[] arrayEnteros = new int[tamano];
    for(int i=0;i?

    Gracias

  • expilu Says:
    January 30th, 2008 at 6:00 am  

    Oh el comentario anterior se cortó…
    Bueno decía que usando int[] (se que poner código ha hecho que se corte el comentario) mis resultados son estos:

    Tiempo Un/Boxing: 7453 Memoria: 494652236
    Tiempo Generics: 1094 Memoria: 201774748
    Tiempo int[]: 438 Memoria: 120448104

    Veo que usar int[] es más rápido que arrayList y List… pero ¿cuales serían las deficiencias de usar un array (no arraylist) con respecto a List?

  • JuanK Says:
    January 30th, 2008 at 8:23 am  

    Hola,
    realmente hay una gran diferencia…
    un array NO es redimensionable, una colección si es redimensionable, desde luego si nunca vas a cambiar el tamaño de un arreglo lo mejor es usar array, pero lo usual es que si debes cambiarle de tamaño.

  • komoloves Says:
    February 19th, 2008 at 6:18 am  

    buen trabajo, la verdad que estoy de acuerdo contigo.

  • kiser_lx Says:
    May 6th, 2009 at 4:02 am  

    Hola,
    veo que el uso de memoria mejora al utilizar el Colletc, pero es recomendable?? COn esta instrucción fuerzas al paso del recolector de basura y pierdes las posibles optimizaciones que este usa en su paso por el rpograma. Es un uso abrasivo de la instrucción.
    Un saludo

  • JuanK Says:
    May 6th, 2009 at 8:51 am  

    No es recomendable, solo lo hice para hacer las mediciones. En condiciones normales nunca necesitaras o deberás usar algo así.

  • Fsigu Says:
    June 30th, 2009 at 5:37 pm  

    muy bueno esta entrada, seria buenisimo si pudiers poner un buen ejemplo de uso de generics en capas ya en una consulta a la base de datos, con eso ayudarias a mucha gente incluyendome a saber como realmente usar generics.

    Saludos

  • Aridane Says:
    December 1st, 2011 at 7:51 am  

    Yo lo que entiendo es que al usar generics la resolución del boxing es en tiempo de compilación no de ejecución, de ahí la mejora del rendimiento.

Deja un comentario

Redes Sociales

Follow @JuanKRuiz
Answer Questions

Busca en el blog

Artículos Relacionados

  • Optimización de Código – Cómo Convertir un Entero en Binario – C#
  • Optimización de Código – Diferencia entre usar Convert y usar cast – C#
  • C# – Cuando la precisión que da el StopWatch no es suficiente…
  • C# – la palabra clave volatile, explicación y ejemplos
  • Artículos Relacionados

  • Optimización de Código – Cómo Convertir un Entero en Binario – C#
  • Optimización de Código – Diferencia entre usar Convert y usar cast – C#
  • C# – Cuando la precisión que da el StopWatch no es suficiente…
  • C# – la palabra clave volatile, explicación y ejemplos
  • Nube de Temas

    API - C# - codigo - Fiber - Forms - GeSHi - icon - icono - IE - IE9 - imagenes - IT - operativo - Pinned - PowerShell - Proceso - rendimiento - RSS - sistema - Sistemas Operativos - Site - stack - Thread - velocidad - Visual - WCF - Windows - WndProc - WPF - XNA

    Blogs recomendados

  • VBCodigoPocketPC Espacio para tratar temas de programacion para dispositivos moviles, Pocket PC, Compact Framework, Embbeded Visual Basic, Visual Basic.NET , C# (C Sharp)
  • Róbinson Moscoso Estaré publicando acá cosas sobre tecnologia .NET, situacioines cotidianas de las que voy aprendiendo… sirve como extensión de memoria.
  • .Net C# Blog de Nelsón Venegas
  • Warnov Microsoft Developer Evangelist
  • IT LIfe Blog de mi Hermano que esta en el lado claro: IT
  • Sorey Garcia Una chica del común con la firme intención de no serlo
  • Black Byte videojuegos, modelado y animación 3d
  • Road to IT World Cosas interesantes de IT
  • Marcela Chitiva Un poco de esto… un poco de aquello
  • Surviving the Nigth El mejor blog para aquellos que nos gustan los “internals”
  • Meta

    1. Log in
    2. WordPress

    Ideas de un Conejo is powered by Wordpress. Theme designed by Juan Carlos Ruiz.