Bellow es mi respuesta, pero también tenga en cuenta que Jon Skeet habló sobre esto hoy en su blog y sobre el hecho de que no está totalmente de acuerdo con el significado de MSDN de "Lazy" ya que MSDN no está realmente claro de qué perezoso exactamente significa cuando lo usan en Just how lazy are you ? su publicación para una lectura interesante.
Además Wikipedia suponer que tres normas deben mantenerse para la evaluación perezosa y tercer punto no se respeta en el sentido de MSDN que la expresión se evaluará más de una vez si GetEnumerator
se llama de nuevo (Por la especificación de reinicio no se ha implementado en el empadronador objetos generados usando la palabra clave yield
y la mayoría de LINQ utilizarlo actualmente)
Teniendo en cuenta una función
int Computation(int index)
ejecución inmediata
IEnumerable<int> GetComputation(int maxIndex)
{
var result = new int[maxIndex];
for(int i = 0; i < maxIndex; i++)
{
result[i] = Computation(i);
}
return result;
}
- Cuando se invoca la función se ejecuta
Computation
maxIndex
veces
GetEnumerator
devuelve una nueva instancia del empadronador no hacer nada más.
- Cada llamada a
MoveNext
pone el valor almacenado en la siguiente celda de la matriz en el miembro Current
de IEnumerator
y eso es todo.
Costo: Big adelantado, Pequeño durante la enumeración (sólo una copia)
diferido pero la ejecución ansiosos
IEnumerable<int> GetComputation(int maxIndex)
{
var result = new int[maxIndex];
for(int i = 0; i < maxIndex; i++)
{
result[i] = Computation(i);
}
foreach(var value in result)
{
yield return value;
}
}
- Cuando la función se llama una instancia de una clase de auto generada (llamado "objeto enumerable" en la especificación) que implementa
IEnumerable
se crea y se almacena una copia del argumento (maxIndex
).
GetEnumerator
devuelve una nueva instancia del enumerador sin hacer nada más.
- La primera llamada a
MoveNext
ejecuta maxIndex por el método de cálculo, almacena el resultado en una matriz y Current
devolverá el primer valor.
- Cada llamada subsiguiente a
MoveNext
pondrá en Current
un valor almacenado en la matriz.
Costo: nada por adelantado, Big cuando el inicio enumeración, Pequeño durante la enumeración (sólo una copia)
diferido y ejecución perezoso
IEnumerable<int> GetComputation(int maxIndex)
{
for(int i = 0; i < maxIndex; i++)
{
yield return Computation(i);
}
}
- Cuando la función se llama el lo mismo que sucede con el caso de ejecución perezosa.
GetEnumerator
devuelve una nueva instancia del enumerador sin hacer nada más.
- Cada llamada a
MoveNext
ejecutar una vez el código Computation
, poner el valor en Current
y dejar que la persona que llama actúe inmediatamente sobre el resultado.
La mayoría de los linq usan ejecución diferida y lenta, pero algunas funciones no pueden ser tan parecidas a las de ordenación.
Costo: nada por adelantado, moderado durante la enumeración (el cálculo se ejecuta allí)
En resumen
- inmediata significa que el cálculo/la ejecución se realiza en la función y terminó una vez que la función regreso. (Totalmente eager evaluación ya que la mayoría código C# hace)
- diferido/Eager quiere decir que la mayor parte del trabajo se realizará en la primera
MoveNext
o cuando se crea la instancia IEnumerator
(Para IEnumerable
es cuando GetEnumerator
se llama)
- diferido/Lazy significa que el trabajo se realizará cada vez que se llame a
MoveNext
pero nada antes.
Parallel LINQ lo hace un poco diferente que podría ser considerado el cálculo diferido/Lazy desde el punto de vista de la persona que llama pero internamente el cálculo de un número de elementos comienzan en paralelo, tan pronto como comience la enumeración. El resultado es que si el siguiente valor ya está allí lo obtienes inmediatamente, pero de lo contrario tendrás que esperarlo.
Ho Joel Martinez, muchas gracias por su respuesta. –
¡No tan rápido! Esto no funcionará para datos relacionales. –
¿Qué tienen que ver los datos relacionales con la evaluación entusiasta de un ienumerable? incluso si lo ienumerable está en contra de algo como linq2sql o ef, iterará todos los registros en la memoria (lo que le permite cerrar la conexión db antes). –