W poprzednim wpisie opisałem extension methods, dzisiaj czas na kolejny element moim zdaniem bardzo ważny do zrozumienia działania linq mianowicie słowo kluczowe yield.
Dla przypomnienia Linq jest połączeniem 5 elementów:
Zasadę działania słowa kluczowego yield najlepiej zobrazuje przykład. Załóżmy, że mamy metodę, która generuje kolekcję danych, w naszym przypadku intów, wygenerowanie każdego elementu trwa 1 ms.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public static class Yielding { public static IEnumerable<int> GenerateNumbers() { var numbers = new List<int>(); for (int i = 1; i <= 100; i++) { //symulacja operacji czasochłonnej Thread.Sleep(1); numbers.Add(i); } return numbers; } } |
Teraz załóżmy, ze chcemy znaleźć liczby pierwsze (patrz poprzedni post), ale tylko wśród pierwszych 50 elementów kolekcji.
1 2 3 4 5 6 7 8 9 10 |
static void Main(string[] args) { foreach (var number in Yielding.GenerateNumbers() ) { if(number==50) return; Console.WriteLine("{0} is prime {1}", number, number.IsPrime()); } } |
Jak długo będzie wykonywała się ta metoda? Ok 100 ms ponieważ tyle trwa generowanie danych. Tylko nie potrzebnie generujemy połowę danych. Jak to przyśpieszyć? Tutaj właśnie przychodzi nam z pomocą yield a w tym konkretnym przypadku yield return
Zmodyfikowana metoda:
1 2 3 4 5 6 7 8 9 10 |
public static IEnumerable<int> GenerateNumbers() { for (int i = 1; i <= 100; i++) { //symulacja operacji czasochłonnej Thread.Sleep(1); yield return i; } } |
Yield return powoduje wstrzymanie iteracji przekazując odpowiednią wartość do enumeratora (obiektu, który obsługuje iteracje po kolekcji) i zwraca sterowanie do metody która ją wywołuje w tym przypadku Main. Jak teraz zachowuje się nasz program? Program wykonuje się w ok 50Ms oraz wyniki pojawiają się na ekranie od razu, wcześniej trzeba było poczekać aż wygenerowane zostaną dane a później następowało sprawdzenie czy liczba jest liczbą pierwszą.
Utworzyliśmy właśnie tzw. leniwą kolekcję tzn. taką, która zwraca kolejny element, wtedy kiedy jest on potrzebny. Mechanizm ten jest namiętnie wykorzystywany w linq czego przykłady pojawią się w kolejnych wpisach.
3 Komentarze
Wedlock
16 sierpnia 2013 na 08:54 (UTC 2) Link do tego komentarza
a nie dało by się częściej pisać ? zamierzałem do LINQ się dosiąść a skoro tu mam okazję to z chęcią zassał bym nową wiedzę
graf
16 sierpnia 2013 na 10:25 (UTC 2) Link do tego komentarza
Planowalem dodawac dwa wpisy tygodniowo, ale jesli bedzie wieksze zainteresowanie to pewnie zwieksze czestotliwosc;)
Mateusz
9 września 2013 na 13:34 (UTC 2) Link do tego komentarza
Ja również przyłączyłbym się do większej częstotliwości wpisów, tym bardziej dla JUNIOR DEV