Reactive extensions

1,517 views

Published on

Презентация по реактивным расширениям

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,517
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
24
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • Обращаю внимание, что под «управлением» подразумевается не синхронизация, а «параметризация» определенных методов дополнительными объектами, которые знают, в каком контексте необходимо выполнить определенную операцию. Наиболее типичным примерам такого управления является использование специализированных планировщиков, которые будут вызывать методы наблюдателя в контексте синхронизации.
  • Rx - это клей, "склеивающий" разнородныеасинхронныеисточникиданных.
  • Эта пара интерфейс как раз и представляют ту самую pull-последовательность, о которойшларечьраньше. Перебором элементовпоследовательностизанимаетсявызывающий код. Пользовательдолженвызвать метод MoveNext для перехода к следующемуэлементу, и толькоесли (и когда) он вернулtrue (может пройти полдня, кстати), то нужнообратиться к свойствуCurrent для полученияпоследующегоэлементапоследовательности.Условныеобозначения для рисования: IE - IEnumerable и IR - IEnumeratorСпецификторout в объявлении интерфейсов появился только в .NET 4.0 и означает, что этот интерфейс ковариантный. В данном случае это означает, что из этого интерфейса мы можем «вытягивать» данные, а не помещать их туда. И эта однонаправленность интерфейса позволяет его использовать в коде «полиморфным образом». Например, если у нас есть класс Base и его наследник – класс Derived, то в нашем коде мы можем использовать следующее:Derived d = new Derived();Base b = d;Это означает, что переменную с типом наследника мы можем трактовать, как переменную базового класса, но это совсем не значит, что мы можем трактовать последовательность объектов типа Derived, как последовательность типов Base. Точнее, мы не могли этого делать до появления ковариатности и контравариантностиинтрфейсов.Теперь, если обобщенный параметр объявлен со спецификатором out, то этот параметр становится ковариантным. И все, что применялось к простым переменным (нашим переменным b и d), теперь может применяться к интерфесом: IEnumerable<Derived> и IEnumerable<Base>:IEnumerable<Derived> d = new List<Derived>(); IEnumerable<Base> b = d;
  • Барточеньприкольновыразился, когдасказал, чтозачастуюпаттерны в бандечетырехсгруппированывместе по схожести. Новотсхожестьмеждуитератором и наблюдателемникак не обозначена. В целом, этосвязано с тем, что push-basedколлекцииявляютсялишьчастнымслучаемнаблюдателя, и этотпаттернможетприменяться и в других контекстах. Но, тем не менее, еслипосмотретьподэтимуглом, то симетриямеждуэтимидвумяпаттернамиприсутствует.
  • Первые три слайда показывают семантическую схожесть (или проводят аналогии) между некоторыми встроенными и простыми наблюдаемыми последовательностями и обычными структурами данных и последовательностями.
  • Но прежде чем переходить к небольшой демонстрации, давайте рассмотрим еще несколько важных тем.Во-первых, нам нужно рассмотреть упрощенную версию метода Subscribe, который вместо того, чтобы принимать интерфейс IObserver принимает лямбда-выражение. Кроме того, нам нужно рассмотреть процесс отписки от событий, чтобы рассматриваемые пример были более понятными.
  • Аналогично тому, как вы не можете получить следующий элемент последовательности, пока вы не получили предыдущий, асинхронные последовательности также предоставляют подобные гарантии. (Да, кстати, вы можете добиться этого, но для этого придется попотеть). Точно также, правильная реактивная библиотека, которая следует определенным рекомендациям (существует специальный документ, который называется Rx Design Guidelines) не должна отправлять одному и тому же наблюдателю следующие элемент, пока не завершилась обработка предыдущего элемента.
  • Тут словам можно сказать, что поскольку у нас нет, как в Джаве анонимной реализации интерфейсов, то мы можем это эмулировать с помощью методов расширения
  • Запустить голый проект в Visual Studio 2010 с добавленными ссылками на Rx и показать несколько простых и примитивных примеров. В частности, показать, что при добавлении соответствующей using директивы мы получим множество методов расширения, которые позволят нам использовать LINQ во всей красе.Затем, дать пример, который генерирует последовательность данных и немного с ней поиграться.Добавить простой метод Generateс параметром TimeSpan, показать, что основной поток все еще не заблокирован.Потом запустить Generate с random-ом и поиграться еще. Добавить DistinctUntilChanged();, а потом Buffer с печатью всех элементов, а потом с суммой.
  • Здесь нужно обязательно сказать и, возможно даже показать сложность с отпиской от события. Ведь для нормальной отписки от события
  • Еще одним недостатком событий, о котором следует упомянуть – это отсутствие композиции. Мы не можем отфильтровать данные одного события и сделать из него другое. Для этого нужно добавить совершенно новое событие. А если нам нужно несколько способов манипулирования (фильтрации, получения проекции), то сложность решения резко возрастает.
  • Запустить VS2010 и попробовать отфильтровать события пользовательского интерфейса и показать, что из этого получается.
  • Фраза о том, что Task – это single value asynchrony etc
  • Очень важно сказать, что RX строятсяon top of existing abstractions but they’re not going to replace them. Остается множество мест, где события нужно использовать напрямую, не оборачивая их ни в какие последовательности. Мы кликнули на форме и получили событие загрузки формы, мы никогда не получим множество событий загрузки формы, которые мы хотели бы композировать каким-то хитрым образом. Если нам нужно обработать событие клика мышки, то опять же, нет никакого смысла добавлять что-либо.Точно так же, все существующие примитивы в .NET Framework остаются такими же ценными, какими они были вчера. Никто не собирается изменять низкоуровневый код, который прекрасно работает и заточен лишь для одной цели. Но теперь, работая с ним его легко можно обернуть в более высокоуровневые примитивы и работать с ним с более высокого уровня абстракции.
  • Примеры, посвященные асинхронности.
  • Описать и рассказать об интерфейсе IScheduler, который инкапсулирует в себе вопросы асинхронности и управления ею.По умолчанию используется скеджулер, который называется Immediate, т.е. который не делает никакой многопоточности. И это разумно, поскольку многопоточность не бесплатна. Но практически все операции, типа Return, Range и т.д. принимают дополнительный параметр (т.е. содержат соответствующую перегрузку), который принимает интерфейс Ischeduler.В большинстве случаев об этом параметре можно не думать, поскольку решение по умолчанию нам подходит. Так, например, метод Generate, который принимает еще и TimeSpan по умолчанию использует ThreadPool, поскольку использование текущего потока сделает этот метод бесполезным.
  • А вот здесь показать, как упадет тот же самый пример без асинхронности, но будет жить, когда мы ее добавим контекст синхронизации!
  • Пример из выступления Вейеса!
  • Reactive extensions

    1. 1. Reactive ExtensionsСергей ТепляковSTeplyakov@luxoft.com
    2. 2. О Вашем инструкторе Сергей Тепляков Visual C# MVP, RSDN Team member Sergey.Teplyakov@gmail.com SergeyTeplyakov.blogspot.com 1-2
    3. 3. Необходимая подготовкаСлушатели должны: Быть знакомы с основами языка C# и платформы .Net Обладать базовыми знаниями многопоточности Быть знакомы с LINQ (Language Integrated Query) 1-4
    4. 4. Roadmap Введение в реактивные расширения Дуализм интерфейсов Основы Rx Observable sequences Events и Observables Observables и асинхронные операции Concurrency Новости из Редмонта 1-5
    5. 5. Интерактивная и реактивнаямодель
    6. 6. Реактивное программированиеПарадигма программирования, ориентированная на потокиданных и распространение изменений. Это означает, чтодолжна существовать возможность легко выражатьстатические и динамические потоки данных, а также то, чтовыполняемая модель должна автоматически распространятьизменения сквозь поток данных.http://ru.wikipedia.org//wiki/Реактивное_программирование
    7. 7. Реактивная модель"Принцип Голливуда" – "Не звоните нам, мы сами вампозвоним"(Hollywood Principle - Dont call us, well call you)
    8. 8. Rx - это1. набор классов, представляющих собой асинхронныйпоток данных2. набор операторов, предназначенных дляманипуляции этими данными3. набор классов для управления многопоточностьюRx = Observables + LINQ + Schedulers
    9. 9. Зачем все это нужно? GPS RSS feeds Social media Server management
    10. 10. Интерфейс IEnumerablePull-based последовательности представленыинтерфейсом IEnumerable. Это - коллекции в памяти (списки, вектора и т.д.) бесконечные последовательности (генераторы) xml-данные результаты запроса к БД
    11. 11. Интерфейс IEnumerablepublic interface IEnumerable<out T>{ IEnumerator<T> GetEnumerator();} Ковариантность из .NET 4.0public interface IEnumerator<out T> : IDisposable{ Блокирующая bool MoveNext(); операция T Current { get; } void Reset();}
    12. 12. Упрощение интерфейсаIEnumeratorpublic interface IEnumerator<out T> : IDisposable{ (T | void | Exception) GetNext();} T – следующий элемент void – окончание последовательности Exception – ошибка
    13. 13. Интерфейс IObservablepublic interface IObservable<out T>{ IDisposable Subscribe(IObserver<T> observer);}public interface IObserver<in T>{ void OnNext(T value); void OnError(Exception error); void OnCompleted();}
    14. 14. Pull vs Push
    15. 15. Pull vs Push
    16. 16. Простые последовательности OnCompleteObservable.Empty<int>(); new int[] {}; OnNextObservable.Return(42); new int[] {42}; OnError Итератор,Observable.Throw<int>(ex); генерирующий исключение Итератор, который неObservable.Never<int>(); возвращает управление
    17. 17. Методы RangeObservable.Range(0, 3); OnNext(0) OnNext(1) OnNext(2)Enumerable.Range(0, 3); yield 0 yield 1 yield 2
    18. 18. Циклы forvar xs = Observable.Generate( var xs = new IEnumerable<int> { 0, for(int i = 0; x => x < 10, i < 10; x => x + 1, i++) Предположим, x => x); yield return i; у нас есть }; синтаксис анонимных итераторовxs.Subscribe(x => { foreach(var x in xs) { Console.WriteLine(x); Console.WriteLine(x); } });
    19. 19. Контракт «реактивных»последовательностей Grammar: OnNext* [OnCompleted | OnError] Методы наблюдателя вызываются последовательно
    20. 20. Упрощение работы синтерфейсом IObservervar xs = Observable.Range(0, 10);1. Только OnNext:xs.Subscribe(/*OnNext(int)*/x => Console.WriteLine(x));2. OnNext и OnCompletedxs.Subscribe( /*OnNext(int)*/x => Console.WriteLine(x), /*OnComplete*/() => Console.WriteLine("Completed"));3. OnNext и OnErrorxs.Subscribe( /*OnNext(int)*/x => Console.WriteLine(x), /*OnError(Exception)*/e => Console.WriteLine("Error: {0}", e));4. OnNext, OnError и OnCompletedxs.Subscribe( /*OnNext(int)*/x => Console.WriteLine(x), /*OnError(Exception)*/e => Console.WriteLine("Error: {0}", e), /*OnCompleted*/() => Console.WriteLine("Completed"));
    21. 21. Demo
    22. 22. События в .NET Объявление event Action<int> E; Публикация E(42); Подписка E += x => Console.WriteLine(x);
    23. 23. Rx Объявление ISubject<int> S = new Subject<int>(); Публикация S.OnNext(42); Подписка S.Subscribe(x => Console.WriteLine(x));
    24. 24. Events vs Observablesclass Program { class Program { event Action<int> E; ISubject<int> S = new Subject<int>(); static void Main() { static void Main() { var p = new Program(); var p = new Program(); p.E += x => Console.WriteLine(x); p.S.Subscribe(x => Console.WriteLine(x)); p.E(1); p.S.OnNext(1); p.E(2); p.S.OnNext(2); p.E(3); p.S.OnNext(3); } }} }
    25. 25. Отписка от событий Eventsstatic event Action<string> E;//E += x => Console.WriteLine(x);Action<string> action = x => Console.WriteLine(x);E += action;E -= action; Observablesstatic ISubject<int> S = new Subject<int>();var token = S.Subscribe(x => Console.WriteLine(x));token.Dispose();
    26. 26. «События» первого классаОбъект называют «объектом первого класса» когда он: может быть сохранен в переменной может быть передан в функцию как параметр может быть возвращен из функции как результат может быть создан во время выполнения программы внутренне самоидентифицируем (независим от именования)http://ru.wikipedia.org/wiki/Объект_первого_класса
    27. 27. «События» первого класса// Сохранение в переменнойIObservable<string> textChanged = …;// Передача в качестве параметраvoid ProcessRequests(IObservable<string> input) {…}// Возвращение в качестве результатаIObservable<int> QueryServer() {…}
    28. 28. Возможности наблюдаемыхпоследовательностей Преобразование события в поток объектов PointIObservable<Point> mouseMoves = from e in Observable.FromEventPattern<MouseEventArgs>(frm, "MouseMove") select e.EventArgs.Location; Фильтрация «событий»var filtered = mouseMoves.Where(p => p.X == p.Y); Обработка «событий»var subscription = filtered.Subscribe(p => Console.WriteLine("X, Y = {0}", p.X)); Отписка от «событий»subscription.Dispose();
    29. 29. Demo
    30. 30. Асинхронные операцииClassical Async PatternFileStream fs = File.OpenRead("data.txt"); Невозможность использованияbyte[] buffer = new byte[1024]; привычных языковых конструкций (using, try/finally etc)fs.BeginRead(buffer, 0, buffer.Length, «Вывернутый» поток исполнения ar => { int bytesRead = fs.EndRead(ar); // Обработка данных в массиве buffer }, null); Сложность обработки ошибок, а также чтения и сопровождения кода
    31. 31. FromAsyncPatternstatic int LongRunningFunc(string s){ Thread.Sleep(TimeSpan.FromSeconds(5)); FromAsyncPattern преобразует return s.Length; возвращаемое значение метода в} IObservervable<T>Func<string, int> longRunningFunc = LongRunningFunc;Func<string, IObservable<int>> funcHelper = Observable.FromAsyncPattern<string, int>( longRunningFunc.BeginInvoke, longRunningFunc.EndInvoke);IObservable<int> xs = funcHelper("Hello, String");xs.Subscribe(x => Console.WriteLine("Length is " + x));
    32. 32. Tasks vs FromAsyncPattern Задачи (Tasks) – это унифицированный способ представления Single value asynchrony в .Net Framework Observables – Multi value asynchrony Существует простой способ преобразования Tasks -> Observables
    33. 33. Task -> ToObservable Метод расширения можно написать один раз, а использовать повсюду,static class FuncExtensions а не только с Rx{ internal static Task<int> ToTask(this Func<string, int> func, string s) { return Task<int>.Factory.FromAsync( func.BeginInvoke, func.EndInvoke, s, null); }}Func<string, int> longRunningFunc = LongRunningFunc; Это более предпочтительный способ,string s = "Hello, String"; поскольку метод FromAsyncPattern скоро будет устаревшимIObservable<int> xs = longRunningFunc.ToTask(s).ToObservable();xs.Subscribe(x => Console.WriteLine("Length is " + x), () => Console.WriteLine("Task is finished")); } }
    34. 34. Чем Rx не является Rx не заменяет существующей «асинхронности»:  .NET все еще незаменимы  Асинхронные методы все так же применимы в библиотеках  Задачи представляют собой single value asynchrony  Существуют и другие асинхронные источники, как SSIS, PowerShell, etc Но rx…  Унифицирует работу  Предоставляет возможность композиции  Предоставляет обобщенные операторы Так что rx – это …  Мост!
    35. 35. Demo
    36. 36. Управление многопоточность Управление многопоточностью осуществляется с помощью интерфейса ISchedulervar xs = Observable.Range(0, 10, Scheduler.ThreadPool);xs.Subscribe(x => Console.WriteLine(x)); Параметризация с помощью Будет исполняться в контексте IScheduler доступна в большинстве планировщика операций
    37. 37. Синхронизация Обновление пользовательского интерфейсаLabel lbl = new Label();Form frm = new Form() {Controls = {lbl}};var xs = Observable.Return(42, Scheduler.ThreadPool);xs.Subscribe(x =>{ Thread.Sleep(1000); lbl.Text = "Result is " + x;}); Использование ObserveOnxs.ObserveOn(frm).Subscribe(x =>{ Thread.Sleep(1000); IScheduler поддерживает разные lbl.Text = "Result is " + x; контексты синхронизации});
    38. 38. Demo
    39. 39. Что мы изучили? Введение в реактивные расширения Дуализм интерфейсов Основы Rx Observable sequences Events и Observables Observables и асинхронные операции Concurrency 1-40
    40. 40. Experimental vs Stable Две версии библиотеки Reactive Extensions:  Stable  Experimental Interactive Extensions
    41. 41. Где взять? NuGet Web - http://msdn.microsoft.com/en- us/data/gg577610 Can’t find? Use google
    42. 42. Дополнительные ссылки The Reactive Extensions (Rx)... (Data Developer Center) - http://msdn.microsoft.com/en-us/data/gg577609 Reactive Extensions (MSDN) - http://msdn.microsoft.com/en- us/library/hh242985(v=vs.103).aspx Rx Team Blog - http://blogs.msdn.com/b/rxteam/ Реактивные расширения и асинхронные операции - http://sergeyteplyakov.blogspot.com/2010/11/blog-post.html
    43. 43. Roslyn CTP is awailable!http://msdn.microsoft.com/ru-ru/roslyn
    44. 44. Вопросы?

    ×