Lección 2: Uso de consultas LINQ
Sintaxis y métodos básicos de consultas
Para consultas básicas, el uso de LINQ en Visual Basic o C # es muy fácil e intuitivo ya que ambos lenguajes proporcionan palabras clave que se asignan directamente a las funciones que se han agregado a través de métodos de extensión. La ventaja es que se pueden escribir consultas escribir de una manera muy similar a SQL, obtener el apoyo IntelliSense en todo momento.
Ejemplo: el siguiente horario contiene una lista de los días que están ocupados, y desea saber si está ocupado en un día específico.
--------------------------------------VB------------------------------------------
Private Function GetDates() As List(Of DateTime)
Return New List(Of DateTime) From
{
New DateTime(11, 1, 1),
New DateTime(11, 2, 5),
New DateTime(11, 1, 3),
New DateTime(11, 10, 14),
New DateTime(11, 1, 4)
}
End Function
Dim schedule = GetDates()
Dim areYouAvailable = new DateTime(11, 7, 10)
Dim busy = From d In schedule
Where d = areYouAvailable
Select d
For Each busyDate In busy
txtLog.WriteLine("Lo siento, pero estoy ocupada el {0:MM/dd/yy}", busyDate)
Next
--------------------------------------CS------------------------------------------
private List<DateTime> GetDates()
{
return new List<DateTime>
{
new DateTime(11, 1, 1),
new DateTime(11, 2, 5),
new DateTime(11, 1, 3),
new DateTime(11, 10, 14),
new DateTime(11, 1, 4)
};
}
private void basicLINQToolStripMenuItem_Click(object sender, EventArgs e)
{
var schedule = GetDates();
var areYouAvailable = new DateTime(11,7, 5);
var busy = from d in schedule
where d == areYouAvailable
select d;
foreach(var busyDate in busy)
{
txtLog.WriteLine("Lo siento, pero estoy ocupada el {0:MM/dd/yy}", busyDate);
}
}
El código se podría hacer mas simple, utilizando el metodo where y la consulta queradia de la siguiente forma:
--------------------------------------VB------------------------------------------
Dim schedule = GetDates()
Dim areYouAvailable = New DateTime(11,7,5)
For Each busyDate In schedule.Where(Function(d) d = areYouAvailable)
txtLog.WriteLine("Lo siento, pero estoy ocupada el {0:MM/dd/yy}", busyDate)
Next
--------------------------------------CS------------------------------------------
var schedule = GetDates();
var areYouAvailable = new DateTime(11,7,5);
foreach (var busyDate in schedule.Where(d=>d==areYouAvailable))
{
txtLog.WriteLine("Lo siento, pero estoy ocupada el {0:MM/dd/yy}", busyDate);
}
Palabras clave de LINQ
A continuación se muestra una lista de palabras clave disponibles en LinQ, con una pequeña descripción de cada una:
Cláusula | Descripción |
Especifica un origen de datos y una variable de rango (similar a una variable de iteración). | |
Filtra elementos de origen basándose en una o varias expresiones Boolean separadas por operadores lógicos AND y OR (&& o ||). | |
Especifica el tipo y la forma que tendrán los elementos en la secuencia devuelta cuando se ejecute la consulta. | |
Agrupa los resultados de la consulta según un valor de clave especificado. | |
Proporciona un identificador que puede actuar como referencia a los resultados de una cláusula join, group o select. | |
Ordena los resultados de la consulta en orden ascendente o descendente basándose en el comparador predeterminado para el tipo de elemento. | |
Combina dos orígenes de datos basándose en una comparación de igualdad entre dos criterios de coincidencia especificados. | |
Presenta una variable de rango para almacenar los resultados de una subexpresión en una expresión de consulta. | |
Palabra clave contextual en una cláusula join. | |
Palabra clave contextual en una cláusula join. | |
Palabra clave contextual en una cláusula join. | |
Palabra clave contextual en una cláusula group. | |
Palabra clave contextual en una cláusula orderby. | |
Palabra clave contextual en una cláusula orderby. |
Además de las palabras clave que aparecen en la tabla anterior, Visual Basic proporciona palabras clave que C # no implementa.
Cláusula | Descripción |
Distinct | filtra elementos duplicados |
Skip/Skip While | Salta por encima de algunos elementos antes de devolver los resultados |
Take/Take While | limita cuantos elementos se deben retornar |
Aggregate | Incluye funciones de agregado en las consultas |
All | determina si todos los elementos cumplen con el criterio especificado |
Any | si alguno de los elementos cumple con el criterio especificado |
Average | palabra clave contextual en la cláusula Aggregate que calcula el valor promedio |
Count | número de elementos que cumplen con el criterio especificado |
Group | Palabra clave contextual en la cláusula Aggregate que proporciona acceso a los resultados de un grupo o a la cláusula group join. |
LongCount | número de elementos que cumplen con el criterio especificado (en long) |
Max | Palabra clave contextual en la cláusula Aggregate que proporciona el valor máximo |
Min | Palabra clave contextual en la cláusula Aggregate que proporciona el valor mínimo |
Sum | Palabra clave contextual en la cláusula Aggregate que proporciona la suma de los elementos |
Todos los métodos de extensión consulta están disponibles en ambos idiomas, incluso si no hay un mapeo de lenguaje palabra clave para el método de extensión de la consulta.
Proyecciones
Permiten transformar la salida de la consulta de LINQ usando tipo anonymouns.
Usando la palabra clave Let para ayudar a las proyecciones
Puede utilizar la palabra clave let para crear una variable temporal dentro de la consulta de LINQ. Let es como una variante de la palabra clave SELECT utilizada en la consulta:
--------------------------------------VB------------------------------------------
Dim cars = GetCars()
Dim vinsAndMakes = From c In cars
Let makeModel = c.Make & " " & c.Model
Where makeModel.Contains("B")
Select New With
{
c.VIN,
.MakeModel = makeModel
}
For Each item In vinsAndMakes
txtLog.WriteLine("VIN:{0} Make and Model:{1}", item.VIN, item.MakeModel)
Next
--------------------------------------CS------------------------------------------
var cars = GetCars();
var vinsAndMakes = from c in cars
let makeModel = c.Make + " " + c.Model
where makeModel.Contains('B')
select new { c.VIN, MakeModel=makeModel };
foreach (var item in vinsAndMakes)
{
txtLog.WriteLine("VIN:{0} Make and Model:{1}", item.VIN, item.MakeModel);
}
Resultado:
VIN:DEF123 Make and Model:BMW Z-3
VIN:HIJ123 Make and Model:VW Bug
Especificando un filtro
C # y Visual Basic tienen palabras clave que se corresponden directamente con el método de extensión en la consulta. Se puede especificar un predicado (expresión que se evalúa como un valor booleano) para determinar los elementos que se devuelven, como vimos en el ejemplo anterior.
Especificando un Tipo de ordenación
La palabra clave orderby permite ordenar ascendente o descendente. Además, se puede ordenar en varias propiedades para realizar una ordenación compuesta.
--------------------------------------VB------------------------------------------
Dim cars = GetCars()
Dim sorted = From c In cars
Order By c.Make Ascending, c.Model Descending
Select c
For Each myCar In sorted
txtLog.WriteLine("Car VIN:{0}, Make:{1}, Model:{2} Year:{3}",
myCar.VIN, myCar.Make, myCar.Model, myCar.Year)
Next
End Sub
--------------------------------------CS------------------------------------------
var cars = GetCars();
var sorted = from c in cars
orderby c.Make ascending, c.Model descending
select c;
foreach (var myCar in sorted)
{
txtLog.WriteLine("Car VIN:{0}, Make:{1}, Model:{2} Year:{3}",
myCar.VIN, myCar.Make, myCar.Model, myCar.Year);
}
El resultado seria:
Car VIN:ABC456, Make:Audi, Model:TT Year:2008
Car VIN:DEF123, Make:BMW, Model:Z-3 Year:2005
Car VIN:ABC123, Make:Ford, Model:F-250 Year:2000
Car VIN:DEF456, Make:Ford, Model:F-150 Year:1998
Car VIN:HIJ123, Make:VW, Model:Bug Year:1956
Paginación
La capacidad de observar los datos de una página a la vez es siempre un requisito cuando una gran cantidad de datos ha sido recuperado. Visual Basic ofrece los siguientes métodos de extensión como palabras clave.
--------------------------------------VB------------------------------------------
Dim pageSize = 10
'se crea 5 copias del arreglo cars - total 25 filas
Dim cars = Enumerable.Range(1, 5) _
.SelectMany(Function(i) GetCars() _
.Select(Function(c) New With _
{.BatchNumber = i, c.VIN, c.Make, c.Model, c.Year}))
'calcula el page count
Dim pageCount = (cars.Count() / pageSize)
If (pageCount * pageSize < cars.Count()) Then pageCount += 1
For i = 0 To pageCount
txtLog.WriteLine("-----Pagina {0}------", i)
'con LINQ: Dim currentPage = cars.Skip(i * pageSize).Take(pageSize)
Dim currentPage = From c In cars
Skip (i * pageSize)
Take pageSize
Select c
For Each myCar In currentPage
txtLog.WriteLine("#{0} Car VIN:{1}, Make:{2}, Model:{3} Year:{4}", _
myCar.BatchNumber, myCar.VIN, myCar.Make, myCar.Model, myCar.Year)
Next
Next
--------------------------------------CS------------------------------------------
int pageSize = 10;
//se crea 5 copias del arreglo cars - total 25 filas
var cars = Enumerable.Range(1,5)
.SelectMany(i=>GetCars()
.Select(c=>(new {BatchNumber=i, c.VIN, c.Make, c.Model, c.Year})));
//calcula el page count
int pageCount = (cars.Count() / pageSize);
if (pageCount * pageSize < cars.Count()) pageCount++;
for(int i=0; i < pageCount; i++)
{
txtLog.WriteLine("-----Pagina {0}------", i);
var currentPage = cars.Skip(i * pageSize).Take(pageSize);
foreach (var myCar in currentPage)
{
txtLog.WriteLine("#{0} Car VIN:{1}, Make:{2}, Model:{3} Year:{4}",
myCar.BatchNumber, myCar.VIN, myCar.Make, myCar.Model, myCar.Year);
}
}
Resultado:
-----Pagina 0------
#1 Car VIN:ABC123, Make:Ford, Model:F-250 Year:2000
#1 Car VIN:DEF123, Make:BMW, Model:Z-3 Year:2005
#1 Car VIN:ABC456, Make:Audi, Model:TT Year:2008
#1 Car VIN:HIJ123, Make:VW, Model:Bug Year:1956
#1 Car VIN:DEF456, Make:Ford, Model:F-150 Year:1998
#2 Car VIN:ABC123, Make:Ford, Model:F-250 Year:2000
#2 Car VIN:DEF123, Make:BMW, Model:Z-3 Year:2005
#2 Car VIN:ABC456, Make:Audi, Model:TT Year:2008
#2 Car VIN:HIJ123, Make:VW, Model:Bug Year:1956
#2 Car VIN:DEF456, Make:Ford, Model:F-150 Year:1998
-----Pagina 1------
#3 Car VIN:ABC123, Make:Ford, Model:F-250 Year:2000
#3 Car VIN:DEF123, Make:BMW, Model:Z-3 Year:2005
#3 Car VIN:ABC456, Make:Audi, Model:TT Year:2008
#3 Car VIN:HIJ123, Make:VW, Model:Bug Year:1956
#3 Car VIN:DEF456, Make:Ford, Model:F-150 Year:1998
#4 Car VIN:ABC123, Make:Ford, Model:F-250 Year:2000
#4 Car VIN:DEF123, Make:BMW, Model:Z-3 Year:2005
#4 Car VIN:ABC456, Make:Audi, Model:TT Year:2008
#4 Car VIN:HIJ123, Make:VW, Model:Bug Year:1956
#4 Car VIN:DEF456, Make:Ford, Model:F-150 Year:1998
-----Pagina 2------
#5 Car VIN:ABC123, Make:Ford, Model:F-250 Year:2000
#5 Car VIN:DEF123, Make:BMW, Model:Z-3 Year:2005
#5 Car VIN:ABC456, Make:Audi, Model:TT Year:2008
#5 Car VIN:HIJ123, Make:VW, Model:Bug Year:1956
#5 Car VIN:DEF456, Make:Ford, Model:F-150 Year:1998
Joins
Cuando se trabaja con bases de datos, normalmente se quieren combinar datos de varias tablas para producir un conjunto de resultados combinados. LINQ permite unir dos fuentes genéricas IEnumerable, aunque estas fuentes no sean de una base de datos. Hay tres tipos de uniones: inner joins, outer joins, y cross joins.
Inner joins
Producen una salida sólo si hay una coincidencia entre ambas fuentes.
Ejemplo: una colección de coches se une a una serie de reparaciones, a través del VIN del vehículo:
--------------------------------------VB------------------------------------------
Public Class Repair
Public Property VIN() As String
Public Property Desc() As String
Public Property Cost As Decimal
End Class
Private Function GetRepairs() As List(Of Repair)
Return New List(Of Repair) From
{
New Repair With {.VIN = "ABC123", .Desc = "Change Oil", .Cost = 29.99},
New Repair With {.VIN = "DEF123", .Desc = "Rotate Tires", .Cost = 19.99},
New Repair With {.VIN = "HIJ123", .Desc = "Replace Brakes", .Cost = 200},
New Repair With {.VIN = "DEF456", .Desc = "Alignment", .Cost = 30},
New Repair With {.VIN = "ABC123", .Desc = "Fix Flat Tire", .Cost = 15},
New Repair With {.VIN = "DEF123", .Desc = "Fix Windshield", .Cost = 420},
New Repair With {.VIN = "ABC123", .Desc = "Replace Wipers", .Cost = 20},
New Repair With {.VIN = "HIJ123", .Desc = "Replace Tires", .Cost = 1000},
New Repair With {.VIN = "DEF456", .Desc = "Change Oil", .Cost = 30}
}
End Function
Dim cars = GetCars()
Dim repairs = GetRepairs()
Dim carsWithRepairs = From c In cars
Join r In repairs
On c.VIN Equals r.VIN
Order By c.VIN, r.Cost
Select New With
{
c.VIN,
c.Make,
r.Desc,
r.Cost
}
For Each item In carsWithRepairs
txtLog.WriteLine("Car VIN:{0}, Make:{1}, Description:{2} Cost:{3:C}",
item.VIN, item.Make, item.Desc, item.Cost)
Next
--------------------------------------CS------------------------------------------
public class Repair
{
public string VIN { get; set; }
public string Desc { get; set; }
public decimal Cost { get; set; }
}
private List<Repair> GetRepairs()
{
return new List<Repair>
{
new Repair {VIN = "ABC123", Desc = "Change Oil", Cost = 29.99m},
new Repair {VIN = "DEF123", Desc = "Rotate Tires", Cost =19.99m},
new Repair {VIN = "HIJ123", Desc = "Replace Brakes", Cost = 200},
new Repair {VIN = "DEF456", Desc = "Alignment", Cost = 30},
new Repair {VIN = "ABC123", Desc = "Fix Flat Tire", Cost = 15},
new Repair {VIN = "DEF123", Desc = "Fix Windshield", Cost =420},
new Repair {VIN = "ABC123", Desc = "Replace Wipers", Cost = 20},
new Repair {VIN = "HIJ123", Desc = "Replace Tires", Cost = 1000},
new Repair {VIN = "DEF456", Desc = "Change Oil", Cost = 30}
};
}
var cars = GetCars();
var repairs = GetRepairs();
var carsWithRepairs = from c in cars
join r in repairs
on c.VIN equals r.VIN
orderby c.VIN, r.Cost
select new
{
c.VIN,
c.Make,
r.Desc,
r.Cost
};
foreach (var item in carsWithRepairs)
{
txtLog.WriteLine("Car VIN:{0}, Make:{1}, Description:{2} Cost:{3:C}",
item.VIN, item.Make, item.Desc, item.Cost);
}
El resultado seria:
Car VIN:ABC123, Make:Ford, Description:Fix Flat Tire Cost:$15.00
Car VIN:ABC123, Make:Ford, Description:Replace Wipers Cost:$20.00
Car VIN:ABC123, Make:Ford, Description:Change Oil Cost:$29.99
Car VIN:DEF123, Make:BMW, Description:Rotate Tires Cost:$19.99
Car VIN:DEF123, Make:BMW, Description:Fix Windshield Cost:$420.00
Car VIN:DEF456, Make:Ford, Description:Alignment Cost:$30.00
Car VIN:DEF456, Make:Ford, Description:Change Oil Cost:$30.00
Car VIN:HIJ123, Make:VW, Description:Replace Brakes Cost:$200.00
Car VIN:HIJ123, Make:VW, Description:Replace Tires Cost:$1,000.00
Al mirar el resultado de esta consulta, el auto con el VIN de ABC456 no tenía reparación, por lo que no se muestra.
Outer Joins
Devuelve todas las filas de una de las tablas, siempre que tales filas cumplan con alguna de las condiciones de búsqueda de WHERE o HAVING.
La cláusula into crea un identificador que puede servir como una referencia a los resultados de un join , group, o select. Las referencias de la unión se asignan a la variable temp.
--------------------------------------VB------------------------------------------
Dim cars = GetCars()
Dim repairs = GetRepairs()
Dim carsWithRepairs = From c In cars
Group Join rep In repairs
On c.VIN Equals rep.VIN Into temp = Group
From r In temp.DefaultIfEmpty()
Order By c.VIN, If(r Is Nothing, 0, r.Cost)
Select New With
{
c.VIN,
c.Make,
.Desc = If(r Is Nothing, _
"***Sin Reparaciones***", r.Desc),
.Cost = If(r Is Nothing, _
0, r.Cost)
}
For Each item In carsWithRepairs
txtLog.WriteLine("Car VIN:{0}, Make:{1}, Descripcion:{2} Cost:{3:C}",
item.VIN, item.Make, item.Desc, item.Cost)
Next
--------------------------------------CS------------------------------------------
var cars = GetCars();
var repairs = GetRepairs();
var carsWithRepairs = from c in cars
join r in repairs
on c.VIN equals r.VIN into g
from r in g.DefaultIfEmpty()
orderby c.VIN, r==null?0:r.Cost
select new
{
c.VIN,
c.Make,
Desc = r==null?"***Sin Reparaciones***":r.Desc,
Cost = r==null?0:r.Cost
};
foreach (var item in carsWithRepairs)
{
txtLog.WriteLine("Car VIN:{0}, Make:{1}, Descripcion:{2} Cost:{3:C}",
item.VIN, item.Make, item.Desc, item.Cost);
}
El resultado seria:
Car VIN:ABC123, Make:Ford, Description:Fix Flat Tire Cost:$15.00
Car VIN:ABC123, Make:Ford, Description:Replace Wipers Cost:$20.00
Car VIN:ABC123, Make:Ford, Description:Change Oil Cost:$29.99
Car VIN:ABC456, Make:Audi, Description:***Sin Reparaciones*** Cost:$0.00
Car VIN:DEF123, Make:BMW, Description:Rotate Tires Cost:$19.99
Car VIN:DEF123, Make:BMW, Description:Fix Windshield Cost:$420.00
Car VIN:DEF456, Make:Ford, Description:Alignment Cost:$30.00
Car VIN:DEF456, Make:Ford, Description:Change Oil Cost:$30.00
Car VIN:HIJ123, Make:VW, Description:Replace Brakes Cost:$200.00
Car VIN:HIJ123, Make:VW, Description:Replace Tires Cost:$1,000.00
Cross Joins
Una combinación cruzada es un producto cartesiano entre dos fuentes.Un producto cartesiano unirá a cada registro del origen de los elementos exteriores con todos los elementos de la fuente interior. No se requieren claves de unión con este tipo de unión.
--------------------------------------VB------------------------------------------
Dim cars = GetCars()
Dim colors() = {"Red", "Yellow", "Blue", "Green"}
Dim carsWithRepairs = From car In cars
From color In colors
Order By car.VIN, color
Select New With
{
car.VIN,
car.Make,
car.Model,
.Color = color
}
For Each item In carsWithRepairs
txtLog.WriteLine("Car VIN:{0}, Make:{1}, Model:{2} Color:{3}",
item.VIN, item.Make, item.Model, item.Color)
Next
--------------------------------------CS------------------------------------------
var cars = GetCars();
var colors = new string[]{"Red","Yellow","Blue","Green" };
var carsWithRepairs = from car in cars
from color in colors
orderby car.VIN, color
select new
{
car.VIN,
car.Make,
car.Model,
Color=color
};
foreach (var item in carsWithRepairs)
{
txtLog.WriteLine("Car VIN:{0}, Make:{1}, Model:{2} Color:{3}",
item.VIN, item.Make, item.Model, item.Color);
}
La combinación cruzada produce una salida para cada combinación de entradas, lo que significa que es el numero de entradas de la primera multiplicada por el número de las entradas de la segunda tabla. Otra forma de implementar una combinación cruzada es utilizar el método de consulta de extensión SelectMany.
Agrupación y agregación
LINQ permite calcular los agregados para cada elemento mediante el uso de la cláusula group by.
--------------------------------------VB------------------------------------------
Dim repairs = From r In GetRepairs()
Group By VIN = r.VIN
Into grouped = Group, TotalCost = Sum(r.Cost)
For Each item In repairs
txtLog.WriteLine("Car VIN:{0}, TotalCost:{1:C}",
item.VIN, item.TotalCost)
Next
--------------------------------------CS------------------------------------------
var repairs = from r in GetRepairs()
group r by r.VIN into grouped
select new
{
VIN = grouped.Key,
TotalCost = grouped.Sum(c => c.Cost)
};
foreach (var item in repairs)
{
txtLog.WriteLine("Car VIN:{0}, Total Cost:{1:C}",
item.VIN, item.TotalCost);
}
El resultado seria:
Car VIN:ABC123, Total Cost:$64.99
Car VIN:DEF123, Total Cost:$439.99
Car VIN:HIJ123, Total Cost:$1,200.00
Car VIN:DEF456, Total Cost:$60.00
Esta consulta produce el costo total de las reparaciones de cada vehículo, pero como un auto no tenía reparación, no figura. Para mostrar todos lo autos, se debe usar left join para unir los autos con la suma de las reparaciones.
--------------------------------------VB------------------------------------------
Dim cars = GetCars()
Dim repairs = GetRepairs()
Dim carsWithRepairs = From c In cars
Group c By Key = New With {c.VIN, c.Make}
Into grouped = Group
Group Join r In repairs On Key.VIN Equals r.VIN
Into joined = Group
Select New With
{
.VIN = Key.VIN,
.Make = Key.Make,
.TotalCost = joined.Sum(Function(x) x.Cost)
}
For Each item In carsWithRepairs
txtLog.WriteLine("Car VIN:{0}, Make:{1}, Total:{2:C}", _
item.VIN, item.Make, item.TotalCost)
Next
--------------------------------------CS------------------------------------------
var cars = GetCars();
var repairs = GetRepairs();
var carsWithRepairs = from c in cars
join rep in repairs
on c.VIN equals rep.VIN into temp
from r in temp.DefaultIfEmpty()
group r by new { c.VIN, c.Make } into grouped
select new
{
VIN = grouped.Key.VIN,
Make = grouped.Key.Make,
TotalCost =
grouped.Sum(c => c == null ? 0 : c.Cost)
};
foreach (var item in carsWithRepairs)
{
txtLog.WriteLine("Car VIN:{0}, Make:{1}, Total:{2:C}",
item.VIN, item.Make, item.TotalCost);
}
}
El resultado es:
Car VIN:ABC123, Make:Ford, Total Cost:$64.99
Car VIN:DEF123, Make:BMW, Total Cost:$439.99
Car VIN:ABC456, Make:Audi, Total Cost:$0.00
Car VIN:HIJ123, Make:VW, Total Cost:$1,200.00
Car VIN:DEF456, Make:Ford, Total Cost:$60.00
Parallel LINQ (PLINQ)
LINQ paralelo, también conocido como PLINQ, es una aplicación paralela de LINQ a objetos. PLINQ implementa todos los métodos de extensión de LINQ y cuenta con operadores adicionales para las operaciones en paralelo.
En muchos escenarios, pero no todos, PLINQ puede proporcionar un aumento significativo en la velocidad mediante el uso de todas las CPU disponibles o núcleos de CPU.
Método de extensión AsParallel
El método de extensión AsParallel divide el trabajo a cada procesador o núcleo del procesador. El siguiente ejemplo de código se inicia con un cronómetro en el espacio de nombres System.Diagnostics para mostrar el tiempo transcurrido cuando esté terminado, y luego la clase Enumerable produce una secuencia de números enteros de 1 a 10.
La llamada al método AsParallel se añade a la fuente de datos. Esto hace que las iteraciones se extiendan a través del procesador disponible y los núcleos del procesador.Luego de una consulta LINQ recupera todos los números pares, pero en la consulta LINQ, la cláusula where llama a un método Compute, que tiene un retardo de un segundo usando la clase Thread, que se encuentra en el espacio de nombres System.Threading.
--------------------------------------VB------------------------------------------
Dim sw As New Stopwatch
sw.Start()
Dim source = Enumerable.Range(1, 10).AsParallel()
Dim evenNums = From num In source
Where Computing(num) Mod 2 = 0
Select num
For Each ev In evenNums
Debug.WriteLine(String.Format("{0} on Thread {1}", _
New Object() {ev, Thread.CurrentThread.GetHashCode}))
Next
sw.Stop()
Debug.WriteLine(String.Format("Done {0}", New Object() {sw.Elapsed}))
--------------------------------------CS------------------------------------------
Stopwatch sw = new Stopwatch();
sw.Start();
var source = Enumerable.Range(1, 10).AsParallel();
var evenNums = from num in source
Lesson 2: Using LINQ Queries CHAPTER 3 227
where Computing(num) % 2 == 0
select num;
foreach (var ev in evenNums)
{
Debug.WriteLine(string.Format("{0} on Thread {1}", ev,
Thread.CurrentThread.GetHashCode()));
}
sw.Stop();
Debug.WriteLine(string.Format("Done {0}", sw.Elapsed));
public int Computing(int num)
{
Debug.WriteLine(string.Format("Computing {0} on Thread {1}", num,
Thread.CurrentThread.GetHashCode()));
Thread.Sleep(1000);
return num;
}
Resultados mostrando los números pares, tiempo total, y el método computing:
Computing 2 on Thread 10
Computing 1 on Thread 6
Computing 3 on Thread 10
Computing 4 on Thread 6
Computing 5 on Thread 10
Computing 6 on Thread 6
Computing 7 on Thread 10
Computing 8 on Thread 6
Computing 9 on Thread 10
Computing 10 on Thread 6
2 on Thread 9
4 on Thread 9
6 on Thread 9
8 on Thread 9
10 on Thread 9
Done 00:00:05.0632071
Método de extensión ForAll
Cuando la consulta se repite con un foreach, cada iteración se sincroniza en el mismo hilo, para ser tratado, uno tras otro en el orden de la secuencia.
Si se desea es realizar cada iteración en paralelo, sin ningún orden específico, utilice el método ForAll . Tiene el mismo efecto que la ejecución de foreach, pero cada iteración esta en un subproceso diferente.
--------------------------------------VB------------------------------------------
sw.Start()
Dim source = Enumerable.Range(1, 10).AsParallel()
Dim evenNums = From num In source
Where Computing(num) Mod 2 = 0
Select num
evenNums.ForAll(Sub(ev) Debug.WriteLine(string.Format(
"{0} on Thread {1}", ev, Thread.CurrentThread.GetHashCode())))
sw.Stop()
Debug.WriteLine((string.Format("Done {0}", New Object() {sw.Elapsed}))
--------------------------------------CS------------------------------------------
Stopwatch sw = new Stopwatch();
sw.Start();
var source = Enumerable.Range(1, 10).AsParallel();
var evenNums = from num in source
where Computing(num) % 2 == 0
select num;
evenNums.ForAll(ev => Debug.WriteLine(string.Format(
"{0} on Thread {1}", ev,
Thread.CurrentThread.GetHashCode())));
sw.Stop();
Debug.WriteLine(string.Format("Done {0}", sw.Elapsed));
quedaría:
Computing 1 on Thread 9
Computing 2 on Thread 10
Computing 3 on Thread 9
2 on Thread 10
Computing 4 on Thread 10
Computing 5 on Thread 9
4 on Thread 10
Computing 6 on Thread 10
Computing 7 on Thread 9
6 on Thread 10
Computing 8 on Thread 10
Computing 9 on Thread 9
8 on Thread 10
Computing 10 on Thread 10
10 on Thread 10
Done 00:00:05.0556551
Método de extensión AsOrdered
A veces, se debe mantener el orden en la consulta, pero aún así desea la ejecución en paralelo.
El siguiente ejemplo muestra cómo se puede agregar esta llamada al método inmediatamente después del método AsParallel para mantener el orden.
--------------------------------------VB------------------------------------------
Dim sw As New Stopwatch
sw.Start()
Dim source = Enumerable.Range(1, 10).AsParallel().AsOrdered()
Dim evenNums = From num In source
Where Computing(num) Mod 2 = 0
Select num
evenNums.ForAll(Sub(ev) Debug.WriteLine(string.Format(
"{0} on Thread {1}", ev, _
Thread.CurrentThread.GetHashCode())))
sw.Stop()
Debug.WriteLine(string.Format("Done {0}", New Object() {sw.Elapsed}))
--------------------------------------CS------------------------------------------
Stopwatch sw = new Stopwatch();
sw.Start();
var source = Enumerable.Range(1, 10).AsParallel().AsOrdered();
var evenNums = from num in source
where Computing(num) % 2 == 0
select num;
evenNums.ForAll(ev => Debug.WriteLine(string.Format(
"{0} on Thread {1}", ev,
Thread.CurrentThread.GetHashCode())));
sw.Stop();
Debug.WriteLine(string.Format("Done {0}", sw.Elapsed))
Resultado:
Computing 2 on Thread 11
Computing 1 on Thread 10
2 on Thread 11
Computing 4 on Thread 11
Computing 3 on Thread 10
4 on Thread 11
Computing 6 on Thread 11
Computing 5 on Thread 10
6 on Thread 11
Computing 8 on Thread 11
Computing 7 on Thread 10
8 on Thread 11
Computing 9 on Thread 11
Computing 10 on Thread 10
10 on Thread 10
Done 00:00:05.2374586
Resumen de la lección
Esta lección proporciona una visión detallada de las clases ADO.NET desconectadas.
■ Puede utilizar consultas LINQ para proporcionar un método de consulta de cualquier tipo IEnumerable genérico.
■ Las consultas LINQ pueden ser más fácil de leer que el uso de métodos de extensión de consulta.
■ No todos los métodos de extensión de consulta mapean con las palabras clave de LINQ,por lo que aún podría ser necesario utilizar métodos de extensión con las consultas LINQ.
■ Las consultas LINQ permiten filtrar, proyectar, ordenar, unir, agrupar y agregar.
■ PLINQ ofrece una implementación paralela de LINQ que puede aumentar el rendimiento de las consultas LINQ.
No hay comentarios:
Publicar un comentario