Szukaj…


Odroczenie wykonania a natychmiastowe wykonanie

Niektóre metody LINQ zwracają obiekt zapytania. Ten obiekt nie przechowuje wyników zapytania; zamiast tego zawiera wszystkie informacje potrzebne do wygenerowania tych wyników:

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

Zapytanie zawiera wywołanie Console.Write , ale nic nie zostało przesłane do konsoli. Jest tak, ponieważ zapytanie nie zostało jeszcze wykonane, a zatem funkcja przekazana do Select nigdy nie została oceniona. Nazywa się to odroczeniem wykonania - wykonanie zapytania jest opóźnione do pewnego momentu.

Inne metody LINQ wymuszają natychmiastowe wykonanie zapytania; te metody wykonują zapytanie i generują jego wartości:

var newList = query.ToList();

W tym momencie funkcja przekazana do Select zostanie oceniona dla każdej wartości z oryginalnej listy, a następujące informacje zostaną przesłane do konsoli:

1 2 3 4 5


Zasadniczo metody LINQ, które zwracają pojedynczą wartość (np. Max lub Count ) lub zwracają obiekt, który faktycznie przechowuje wartości (takie jak ToList lub ToDictionary ), są wykonywane natychmiast.

Metody zwracające IEnumerable<T> lub IQueryable<T> zwracają obiekt zapytania i pozwalają na odroczenie wykonania do późniejszego momentu.

To, czy określona metoda LINQ wymusza natychmiastowe wykonanie zapytania, można znaleźć w witrynie MSDN - C # lub VB.NET .

Tryb strumieniowy (leniwa ocena) vs tryb non-streaming (szybka ocena)

Spośród metod LINQ, które wykorzystują odroczone wykonywanie, niektóre wymagają oceny pojedynczej wartości na raz. Następujący kod:

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}");
}

wyświetli:

3)
każda wartość iteracji: 3
5
każda wartość iteracji: 5
1
każda wartość iteracji: 1
2)
każda wartość iteracji: 2

ponieważ funkcja przekazana do Select jest oceniana przy każdej iteracji foreach . Jest to znane jako tryb przesyłania strumieniowego lub leniwa ocena .


Inne metody LINQ - operatory sortujące i grupujące - wymagają oceny wszystkich wartości, zanim będą mogły zwrócić jakąkolwiek wartość:

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

wyświetli:

3)
5
1
2)
każda wartość iteracji: 1
każda wartość iteracji: 2
każda wartość iteracji: 3
każda wartość iteracji: 5

W tym przypadku, ponieważ wartości muszą być generowane dla foreach w porządku rosnącym, wszystkie elementy muszą najpierw zostać ocenione, aby ustalić, która jest najmniejsza, a która następna najmniejsza i tak dalej. Jest to znane jako tryb bez przesyłania strumieniowego lub szybka ocena .


Niezależnie od tego, czy określona metoda LINQ korzysta z trybu przesyłania strumieniowego, czy bez przesyłania strumieniowego, można znaleźć w witrynie MSDN - C # lub VB.NET .

Korzyści z odroczonego wykonania - budowanie zapytań

Odroczone wykonywanie umożliwia łączenie różnych operacji w celu zbudowania ostatecznego zapytania przed oszacowaniem wartości:

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

Jeśli w tym momencie wykonamy zapytanie:

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

otrzymalibyśmy następujące dane wyjściowe:

2 2 3 4 6 9

Ale możemy zmodyfikować zapytanie, dodając więcej operatorów:

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

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

Wynik:

20 20 40 60

Korzyści z odroczonego wykonania - sprawdzanie bieżących danych

W przypadku odroczonego wykonania, jeśli zmieniane są dane, których dotyczy zapytanie, obiekt zapytania korzysta z danych w momencie wykonania, a nie w momencie definicji.

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

Jeśli w tym momencie wykonamy zapytanie metodą natychmiastową lub foreach , zapytanie będzie działać na liście liczb parzystych.

Jeśli jednak zmienimy wartości na liście:

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

lub nawet jeśli przypiszemy nową listę do data :

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

a następnie wykonać zapytanie, zapytanie będzie działać na nowej wartości data :

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

i wyświetli następujące informacje:

1 9 25 49 81



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow