Wprowadzenie do Reactive eXtensions dla .NET (RX) Autor: Maciej Zbrzezny Rule Financial, Łódzka Grupa Profesjonalistów IT & .NET 2011.11.03
O mnie Nazywam się Maciej Zbrzezny Pracuje w firmie Rule Financial. Tworzę oprogramowanie wykorzystujące platformę .NET(głównie C#). Autor bloga „Programowanie i Technologie” (http://maciej-progtech.blogspot.com/). MCPD Windows Developer 4.0 MCTS ASP.NET 3.5. maciejzbrzezny@gmail.com @MaciejZbrzezny
Dla kogo? Czy zdarzyło Ci się tworzyć aplikacje, które wykorzystywały wywołania asynchroniczne? Czy, wywołania asynchroniczne sprawiły problemy? Czy wolałbyś otrzymywać dane zamiast o każdą daną się dopraszać? Czy znasz LINQ i chciałbyś go wykorzystywać w większym zakresie?
Problem: pobieranie danych Daj mi Dane Przetwarzam Dane
Asynchroniczność Dzisiejszy świat jest asynchroniczny, a my nie chcemy być blokowani Źródeł danych może być wiele, co w przypadku, gdy musimy połączyć dane z wielu z nich Możemy nie być zainteresowaniu wszystkimi danymi jak je wybierać, czy filtrować Jesteśmy przyzwyczajeni do prostych rozwiązań, najłatwiej przeglądać po prostu kolekcje danych
Misja RX The Reactive Extensions (Rx)... ...is a library to compose asynchronous and event-based programs using observable collections and LINQ-style query operators.
Rx … Pozwala na uproszczenie kodu związanego z programowaniem asynchronicznym oraz opartym na zdarzeniach, Daje możliwość komponowania (łączenia) różnych asynchronicznych operacji oraz ich wyników. Oferuje inne podejście do kolekcji oraz zdarzeń. W Rx są one traktowane jako źródła danych, które możemy obserwować.
Skąd wziąć RX? Nie ma RX w .NET 3.5 SP1 ani .NET 4.0, ale: Można dla nich pobrać W .NET 4.0 przygotowano już pewne ułatwienia Rx jest też dostępne dla: Silverlight 4 (5 w experimental release, 3 –starsze wersje RX) Windows Phone 7 (dostępne już w ROM) XNA 3 i 4 (starsze wersje RX, nie będzie wsparcia) Reactive Extensions for JavaScript (RxJS)
Jak pobrać RX Instalka http://www.microsoft.com/download/en/details.aspx?id=2 6649 (trafić do niej można przez MSDN > Learn > Reactive Extensions (http://msdn.microsoft.com/en- us/data/gg577609) > Get it) NuGet (szukamy RX)
Kolekcje
Przypominamy sobie Enumerator public interface IEnumerable<T> { IEnumerator<T> GetEnumerator(); } public interface IEnumerator<T>: IDisposable T Current { get; } bool MoveNext(); void Reset(); Synchroniczny PULL
Przekształcamy … public interface IEnumerable<T> { IEnumerator<T> GetEnumerator(void); } public interface IEnumerator<T>: IDisposable T GetCurrent (void); bool MoveNext(void); void Reset();
Przekształcamy … public interface IEnumerable<T> { (IDisposable & IEnumerator<T> GetEnumerator(void); } public interface IEnumerator<T>: IDisposable T GetCurrent (void); bool MoveNext(void) throws Exception;
Przekształcamy … public interface IEnumerableDual<T> { (IDisposable & IEnumerator<T> GetSetEnumerator( IEnumerator<T>); } public interface IEnumerator<T> T GetCurrent (void); (true | false | Exception) MoveNext(void) throws Exception;
Przekształcamy … public interface IEnumerableDual<T> { IDisposable SetEnumerator( IEnumerator<T>); } public interface IEnumerator<T> T GetCurrent (void); (true | false | Exception) MoveNext(void);
Przekształcamy … public interface IEnumerableDual<T> { IDisposable SetEnumerator( IEnumerator<T>); } public interface IEnumerator<T> T GetCurrent (void); (T| false | Exception) MoveNext(void);
Przekształcamy … public interface IEnumerableDual<T> { IDisposable SetEnumerator( IEnumerator<T>); } public interface IEnumeratorDual<T> void MoveGotNext(T| false | Exception);
Przekształcamy … public interface IEnumerableDual<T> { IDisposable SetEnumerator( IEnumerator<T>); } public interface IEnumeratorDual<T> void GotT(T); void GotException (Exception); void GotNothing ();
Poznajmy IObservable i IObserver public interface IObservable<T> { IDisposable Subscribe( IObserver<T>); } public interface IObserver<T> void OnNext(T); void OnException (Exception); void OnCompleted (); Asynchroniczny PUSH
Obserwowanie i subskrypcja zamiast przeglądania Jestem zainteresowany Danymi (subscribe) Przetwarzam Dane Error Dane KONIEC
Obserwowanie i subskrypcja zamiast przeglądania Konstruujemy / pobieramy IObservable. (W Rx jest wiele metod pomocniczych tworzące IObservable z tablic, list, zdarzeń, ….) Subskrybujemy przekazując nasz obserwator (IObserver) lub odpowiednie delegacje. Wykonujemy „Dispose” na subskrypcji której dłużej nie potrzebujemy client IObservable<T> Subscription 1 OnNext() OnNext() OnNext() Subscription 2 OnNext() OnNext() OnNext()
Do dzieła….
Reactive.Concurrency i Scheduler CurrentThreadScheduler i Scheduler.CurrentThread ImmediateScheduler i Scheduler.Immediate NewThreadScheduler i Scheduler.NewThread TaskPoolScheduler i Scheduler.TaskPool ThreadPoolScheduler i Scheduler.ThreadPool Dodatkowo: System.Reactive.Windows.Threading.dll: DispatcherScheduler System.Reactive.Windows.Forms.dll: ControlScheduler
Iterator rzuca Exception Observables (1) OnCompleted Observable.Empty<int>() Observable.Return(777) Observable.Throw<int>(new Exception("msg")) Observable.Never<int>() Observable.Range(0,2) new int[0] OnNext new int[]{777} Iterator rzuca Exception OnError Iterator zawiesił się OnNext OnNext Enumerable.Range (0,2)
Observables (2) Observable.Interval ( Observable.Generate( TimeSpan.FromMilliseconds (100)); Observable.Generate( 0, i => i < 10, i => i + 1, i => i); Observable.Create<int>( observer => { observer.OnNext( 77 ); observer.OnCompleted(); return ( () => { } ); } ); I inne … Nowa wartość co 100 ms for(int i=0;i<10;i++) yield return i; // dostępne również // z opóźnieniem // czasowym Przekazujemy delegatę o patametrze IObservable Działamy na IObservable Zwracamy delegatę dla Dispose
Do dzieła….
Ciepło – zimno, czyli zimne i ciepłe źródła Zimne – zawsze te same dane po subskrypcji client IObservable<T> 0, 1, 2, 3, … Subscription 1 Subscription 2 0, 1, 2, 3, … Subscribe() client IObservable<T> Mouse Events Ciepłe – zawsze aktualne dane [x1,y1] [x2,y2] … Subscription 1 Subscription 2 [x2,y2] [x3,y3] … Subscribe()
Zdarzenia w .NET niby pożyteczne, łatwe, ale… myForm.MouseMove += (sender, args) => { if (args.Location.X == args.Location.Y) // chcę wywołać inne zdarzenie }. myForm.MouseMove -= /* a co tutaj?? */ Jak przekazywać? Ukryte źródło danych Jak filtrować? Jak obsługiwać błędy ?? Jak komponować zdarzenia? Co z uwalnianiem zasobów?
… obserwowanie jest lepsze Źródło punktów IObservable<Point> mouseMoves = Observable.FromEventPattern<MouseEventArgs> (this, "MouseMove" ) .Select( ev => ev.EventArgs.Location ); var filtered = mouseMoves .Where(pos => pos.X == pos.Y); var subscription = filtered.Subscribe ( …) Subscription.Dispose(); Obiekty można przekazywać Łatwo można filtrować Są inne operatory pozwalające na kompozycję Łatwo zwalniamy zasoby
Operatory LINQ na IObservable IObservable<T> IObservable<T> Where Skip Take Select
Komponowanie strumieni… --A--A--A--| ----B--B--B--| Amb Amb Concat SelectMany Merge Zip CombineLatest ForkJoin --A--A--A--| --A--A--A--| -----------B--B--B--| Concat --A--A--A--B--B--B--| --A--B--C--| --X--Y--Z--| SelectMany -(AX)(AY)(BX)(BY) (AZ)(CX)(BZ)(CY)(CZ)| -A--B--C---| --X--Y--Z--| Merge --AX-BY-CZ--| -A--B--C---| --X--Y--Z--| Zip -(AX)-(BY)-(CZ)--| -A----B--C--| -UWXYZ--| CombineLatest -(AU)(AW)(BX)(BY)(CZ)| -A----B--C--| -UWXYZ--| ForkJoin -----------(CZ)--|
Do dzieła….
Tematy (Subject) Subject może być obserwowany (jest IObservable) Subject jest obserwatorem (jest IObserver) Wariacje: ReplaySubject: - oferuje pełną historię AsyncSubject – oferuje to co zostało wrzucone na końcu i kończy się BehaviorSubject: podobnie jak ReplaySubject ale z pamięcią 1 elementu. IObservable<T> IObservable<T> OnNext OnNext OnNext OnNext Subject OnNext OnNext OnNext OnNext Client
Do dzieła….
Literatura Channel 9 a zwłaszcza: Mike Taulty - Reactive Extensions for .NET for the Rest of Us: http://channel9.msdn.com/Events/DevDays/DevDays-2011- Netherlands/Devdays014 Bart de Smet - DevCamp 2010 Keynote - Rx: Curing your asynchronous programming blues: http://channel9.msdn.com/Blogs/codefest/DC2010T0100- Keynote-Rx-curing-your-asynchronous-programming-blues Data Developer Center > Learn > Reactive Extensions (Rx) > Beginner's Guide to Reactive Extensions for .NET (http://msdn.microsoft.com/en-us/data/gg577611) a zwłaszcza Design Guidelines.
Observables + LINQ + Schedulers Podsumowanie Rx = Observables + LINQ + Schedulers
Rule Financial - szuka C# developer Senior C# developer Developer .NET/Silverlight http://www.rulefinancial.com/careers/global- vacancies.aspx
Dziękuję za uwagę. Pytania?