aelena.com

22 June 2008

Filed under: .NET, Linq — admin @ 22:07

Jugueteando un poco, he creado el siguiente programilla de consola para ver el rendimiento de estas tres opciones. La idea es que en los tres casos se realizan las mismas operaciones contra un mismo array de números.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace VeryBasicLambda
{
class Program
{
static void Main(string[] args)
{
int numIters = 898;
List<long> _tiempos1 = new List<long>();
List<long> _tiempos2 = new List<long>();
List<long> _tiempos3 = new List<long>();
for (int a = 0; a < numIters; a++)
{
// Console.WriteLine(”OPERACION CON METODOS”);
int[] _array = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8,
3, 4, 7, 4, 2, 5, 9, 0, 2, 3, 2,
6, 3, 6, 9, 4, 6, 7, 5, 6, 2, 7, 5};
// apuntamos momento de inicio
TimeSpan inicio = new TimeSpan(DateTime.Now.Ticks);
// expresion lambda basica para ver los elementos mayores que 5
foreach (int i in _array.Where(x => x >= 5))
{ } // Console.WriteLine(i);
// apuntamos momento de terminar
TimeSpan final = new TimeSpan(DateTime.Now.Ticks);
_tiempos1.Add((final - inicio).Ticks);
//Console.WriteLine(”Duracion de la operacion: {0}”,
//    (final - inicio).Ticks);
// Console.WriteLine(” ———————– “);
// Console.WriteLine(”OPERACION CON QUERY”);
inicio = new TimeSpan(DateTime.Now.Ticks);
// hacemos una consulta equivalente a la expression lambda
var biggers = from s in _array
where s >= 5
select s;
foreach (var _ in biggers)
{ } // Console.WriteLine(_);
final = new TimeSpan(DateTime.Now.Ticks);
_tiempos2.Add((final - inicio).Ticks);
//Console.WriteLine(”Duracion de la operacion: {0}”,
//    (final - inicio).Ticks);
//Console.WriteLine(” ———————– “);
// Console.WriteLine(”OPERACION CON PREDICATE”);
inicio = new TimeSpan(DateTime.Now.Ticks);
// usamos un predicado que devuelva los valores que cumplen la condicion
List<int> bigger = _array.ToList().FindAll(BiggerThan);
foreach (int j in bigger)
{ } // Console.WriteLine(j);
final = new TimeSpan(DateTime.Now.Ticks);
_tiempos3.Add((final - inicio).Ticks);
//Console.WriteLine(”Duracion de la operacion: {0}”,
//    (final - inicio).Ticks);
}
Console.WriteLine(“TIEMPO MEDIO PARA OPERACION CON METODOS LINQ : {0} ( {1} )”,
_tiempos1.Sum() / numIters, _tiempos1.Sum());
Console.WriteLine(“TIEMPO MEDIO PARA OPERACION CON QUERY LINQ : {0} ( {1} )”,
_tiempos2.Sum() / numIters, _tiempos2.Sum());
Console.WriteLine(“TIEMPO MEDIO PARA OPERACION PREDICADO : {0} ( {1} )”,
_tiempos3.Sum() / numIters, _tiempos3.Sum());
Console.WriteLine(“Vez que mas se tardó en hacer la operacion 1: {0}, {1}”,
_tiempos1.Max(), _tiempos1.IndexOf(_tiempos1.Max()));
Console.WriteLine(“Vez que mas se tardó en hacer la operacion 2: {0}, {1}”,
_tiempos2.Max(), _tiempos2.IndexOf(_tiempos2.Max()));
Console.WriteLine(“Vez que mas se tardó en hacer la operacion 3: {0}, {1}”,
_tiempos3.Max(), _tiempos3.IndexOf(_tiempos3.Max()));
Console.Read();
}
private static bool BiggerThan(int valor)
{
return valor >= 5;
}
}
}

Esto produce el siguiente resultado:

TIEMPO MEDIO PARA OPERACION CON METODOS LINQ : 111 ( 100000 )TIEMPO MEDIO PARA OPERACION CON QUERY LINQ : 44 ( 40000 )

TIEMPO MEDIO PARA OPERACION PREDICADO : 77 ( 70000 )

Vez que mas se tardó en hacer la operacion 1: 60000, 0

Vez que mas se tardó en hacer la operacion 2: 10000, 315

Vez que mas se tardó en hacer la operacion 3: 20000, 412>

Supongo que será por mi desconocimiento, pero me sorprende que la expresión lambda tarde bastante más que la propia query de linq cuando el código IL que se genera por detrás es idéntico. Supongo que deben ser los objetos que se crean al ejecutar la expresión. Tengo que mirarlo.
Como veis, el programa ejecuta estas operaciones según el valor que indiquemos en numIters. Si ejecutamos dando un valor de 3 a esta variable, veremos que la operación más cara es siempre la primera. De hecho, los resultados son muy ilustrativos:

TIEMPO MEDIO PARA OPERACION CON METODOS LINQ : 13333 ( 40000 )TIEMPO MEDIO PARA OPERACION CON QUERY LINQ : 0 ( 0 )

TIEMPO MEDIO PARA OPERACION PREDICADO : 3333 ( 10000 )

Vez que mas se tardó en hacer la operacion 1: 40000, 0

Vez que mas se tardó en hacer la operacion 2: 0, 0

Vez que mas se tardó en hacer la operacion 3: 10000, 0

De manera que para operaciones ad hoc, se antoja como mejor opción la de una query.