miércoles, 29 de julio de 2009

¿Cómo medir el rendimiento de tus métodos?

Un tema muy importante es el rendimiento de nuestro código, ¿Cuánto tarda en ejecutarse?, ¿Podría hacerlo más rápido aún? éstas preguntas tenemos que tenerlas en cuenta siempre a la hora de programar, por lo que ahora veremos como medirlo mediante un pequeño ejemplo en donde veremos la diferencia entre concatenar con el "+" y hacerlo con una clase del Framework llamada StringBuilder.


  

using System;

using System.Collections.Generic;

using System.Windows.Forms;

using System.Threading;

using System.Text;

 

namespace DemoXml

{

    static class Program

    {

        ///

        /// The main entry point for the application.

        ///

        [STAThread]

        static void Main()

        {

            Test();

        }

 

        //número de vueltas

        static int avgLoops = 10;

 

        //número de concatenaciones

        static int testAppends = 10000;

 

        public static void Test()

        {

            //tres timespan para tener el valor en segundoss

            TimeSpan concatTotal = new TimeSpan();

            TimeSpan concatMaloTotal = new TimeSpan();

            TimeSpan builderTotal = new TimeSpan();

 

            //pintamos un encabezado

            Console.WriteLine("***********************************************************");

            Console.WriteLine("Vuelta | Con mala praxis |     Normal     |  StringBuilder ");

            Console.WriteLine("***********************************************************");

 

            for (int i = 1; i <= avgLoops; i++)

            {

                //en los tres casos sacamos el tiempo actual

                //lo almacenamos en una variable,

                //inmediatamente se ejecuta el método

                //luego se toma el segundo valor de tiempo

                //y por último se restan.

 

                DateTime timeStart1 = DateTime.Now;

                AppendMethod();

                DateTime timeEnd1 = DateTime.Now;

                concatTotal += timeEnd1 - timeStart1;

 

                DateTime timeStart3 = DateTime.Now;

                AppendMethod_Bad();

                DateTime timeEnd3 = DateTime.Now;

                concatMaloTotal += timeEnd3 - timeStart3;

 

                DateTime timeStart2 = DateTime.Now;

                MethodStringBuilder();

                DateTime timeEnd2 = DateTime.Now;

                builderTotal += timeEnd2 - timeStart2;

 

 

                //los escribimos en la consola

                Console.WriteLine("# {0}   |      {1}      |      {2}     |      {3}      ",

                    i.ToString().PadLeft(2, ' '),

                    (timeEnd3 - timeStart3).TotalSeconds.ToString().PadRight(5, '0'),

                    (timeEnd1 - timeStart1).TotalSeconds.ToString().PadRight(5, '0'),

                    (timeEnd2 - timeStart2).TotalSeconds.ToString().PadRight(5, '0'));

 

 

            }

 

            //por ultimo imprimimos los promedios

            Console.WriteLine("***********************************************************");

            Console.WriteLine("Promedios");

 

            Console.WriteLine("Tiempo concatenando (Con mala praxis): {0} segundos.",

                Math.Round(concatMaloTotal.TotalSeconds / avgLoops, 3).ToString().PadRight(5, '0'));

 

            Console.WriteLine("Tiempo concatenando (Normal):          {0} segundos.",

                Math.Round(concatTotal.TotalSeconds / avgLoops, 3).ToString().PadRight(5, '0'));

 

            Console.WriteLine("Tiempo con StringBuilder:              {0} segundos.",

                Math.Round(builderTotal.TotalSeconds / avgLoops, 3).ToString().PadRight(5, '0'));

 

            Console.WriteLine("***********************************************************");

 

            Console.Read();

        }

 

        //metodos originales sin código de pruebas

        private static string AppendMethod_Bad()

        {

            //este metodo concatena valores aleatorios

            //el problema de éste es que la clase Random

            //la instanciamos en cada vuelta, por lo

            //que se produce una perdida de rendimiento

            string result = "";

            for (int i = 0; i <>

            {

                Random rand = new Random(DateTime.Now.Millisecond);

                result += (byte)rand.Next(65, 91);

            }

            return result;

        }

 

        private static string AppendMethod()

        {

            //de mejor forma instanciamos Random

            //antes del ciclo y ejecutamos el Next

            //tantas veces como necesitemos

            string result = "";

            Random rand = new Random(DateTime.Now.Millisecond);

            for (int i = 0; i <>

            {

                result += (byte)rand.Next(65, 91);

            }

            return result;

        }

 

        private static string MethodStringBuilder()

        {

            //Acá podemos ver que el uso del StringBuilder

            //es muy sencillo.

            StringBuilder builder = new StringBuilder();

            Random rand = new Random(DateTime.Now.Millisecond);

            for (int i = 0; i <>

            {

                builder.Append(rand.Next(65, 91));

            }

            return builder.ToString();

        }

    }

}




Vemos que la diferencia es grande utilizando StringBuilder, por lo que es recomendado utilizarlo en dos casos: cuando no sepas la cantidad de vueltas que da el bucle o cuando la el número de vueltas sea significativo.

Gracias por leer

No hay comentarios:

Publicar un comentario