Buscar..


Ejecución diferida vs ejecución inmediata

Algunos métodos LINQ devuelven un objeto de consulta. Este objeto no contiene los resultados de la consulta; en cambio, tiene toda la información necesaria para generar esos resultados:

var list = new List<int>() {1, 2, 3, 4, 5};
var query = list.Select(x => {
    Console.Write($"{x} ");
    return x;
});

La consulta contiene una llamada a Console.Write , pero no se ha Console.Write nada a la consola. Esto se debe a que la consulta aún no se ha ejecutado y, por lo tanto, la función pasada a Select nunca se ha evaluado. Esto se conoce como ejecución diferida: la ejecución de la consulta se retrasa hasta algún punto posterior.

Otros métodos LINQ obligan a una ejecución inmediata de la consulta; Estos métodos ejecutan la consulta y generan sus valores:

var newList = query.ToList();

En este punto, la función que pasó a Select se evaluará para cada valor en la lista original, y lo siguiente se enviará a la consola:

1 2 3 4 5


En general, los métodos LINQ que devuelven un solo valor (como Max o Count ), o que devuelven un objeto que realmente contiene los valores (como ToList o ToDictionary ) se ejecutan inmediatamente.

Los métodos que devuelven un IEnumerable<T> o IQueryable<T> devuelven el objeto de consulta y permiten aplazar la ejecución hasta un punto posterior.

Si un método LINQ particular obliga a una consulta a ejecutarse inmediatamente o no, se puede encontrar en MSDN - C # , o VB.NET .

Modo de transmisión (evaluación perezosa) versus modo sin transmisión (evaluación impaciente)

De los métodos LINQ que utilizan la ejecución diferida, algunos requieren que se evalúe un solo valor a la vez. El siguiente código:

var lst = new List<int>() {3, 5, 1, 2};
var streamingQuery = lst.Select(x => {
    Console.WriteLine(x);
    return x;
});
foreach (var i in streamingQuery) {
    Console.WriteLine($"foreach iteration value: {i}");
}

saldrá:

3
valor de iteración de foreach: 3
5
valor de iteración de foreach: 5
1
valor de iteración de foreach: 1
2
valor de iteración de foreach: 2

porque la función pasada a Select se evalúa en cada iteración del foreach . Esto se conoce como modo de transmisión o evaluación perezosa .


Otros métodos LINQ (operadores de clasificación y agrupación) requieren que se evalúen todos los valores, antes de que puedan devolver cualquier valor:

var nonStreamingQuery = lst.OrderBy(x => {
    Console.WriteLine(x);
    return x;
});
foreach (var i in nonStreamingQuery) {
    Console.WriteLine($"foreach iteration value: {i}");
}

saldrá:

3
5
1
2
valor de iteración de foreach: 1
valor de iteración de foreach: 2
valor de iteración de foreach: 3
valor de iteración de foreach: 5

En este caso, debido a que los valores se deben generar para el foreach en orden ascendente, primero se deben evaluar todos los elementos, para determinar cuál es el más pequeño, y cuál es el siguiente más pequeño, y así sucesivamente. Esto se conoce como modo sin transmisión o evaluación impaciente .


Ya sea que un método LINQ particular use el modo de transmisión por secuencias o no, puede encontrarse en MSDN - C # , o VB.NET .

Beneficios de la ejecución diferida - construcción de consultas

La ejecución diferida permite combinar diferentes operaciones para construir la consulta final, antes de evaluar los valores:

var list = new List<int>() {1,1,2,3,5,8};
var query = list.Select(x => x + 1);

Si ejecutamos la consulta en este punto:

foreach (var x in query) {
    Console.Write($"{x} ");
}

obtendríamos la siguiente salida:

2 2 3 4 6 9

Pero podemos modificar la consulta agregando más operadores:

Console.WriteLine();
query = query.Where(x => x % 2 == 0);
query = query.Select(x => x * 10);

foreach (var x in query) {
    Console.Write($"{x} ");
}

Salida:

20 20 40 60

Beneficios de la ejecución diferida - consultar datos actuales

Con la ejecución diferida, si se cambian los datos a consultar, el objeto de consulta utiliza los datos en el momento de la ejecución, no en el momento de la definición.

var data = new List<int>() {2, 4, 6, 8};
var query = data.Select(x => x * x);

Si ejecutamos la consulta en este punto con un método inmediato o foreach , la consulta operará en la lista de números pares.

Sin embargo, si cambiamos los valores en la lista:

data.Clear();
data.AddRange(new [] {1, 3, 5, 7, 9});

O incluso si asignamos una nueva lista a los data :

data = new List<int>() {1, 3, 5, 7, 9};

y luego ejecute la consulta, la consulta operará en el nuevo valor de los data :

foreach (var x in query) {
    Console.Write($"{x} ");
}

y dará salida a lo siguiente:

1 9 25 49 81



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow