Реактивные расширения
     для чайников
                       Сергей Звягин
                  Ingate Development
           Специально для GetDev.NET
Реактивное программирование
• Реактивное программирование — парадигма
  программирования, ориентированная на потоки
  данных и распространение изменений. Это
  означает, что должна существовать возможность
  легко выражать статические и динамические
  потоки данных, а также то, что выполняемая
  модель должна автоматически распространять
  изменения сквозь поток данных.

http://ru.wikipedia.org/wiki/Реактивное_программирование
Push и Pull
• Существует 2 подхода обработки
  последовательности данных
• При push-подходе цель запрашивает у
  источника содержимое
• При pull-подходе источник информирует
  цель о наличии данных
Push-подход
• Чтение из файла
• Суммирования элементов массива
• Обработка выборки из БД
Pull-подход
•   Обработка действий пользователя
•   Получение данных от веб-сервиса
•   Таймеры
•   Анимация пользовательского интерфейса
Push-подход
• Push-коллекции в .NET реализуются с
  использованием интерфейсов IEnumerable<T>
  и IEnumerator<T>
• Это могут быть коллекции в памяти
  (списки, массивы), бесконечные
  последовательности (генераторы) или наборы
  данных с неизвестным заранее размером
  (выборка из БД)
• LINQ позволяет быстро организовать работу с
  такими коллекциями
Pull-подход
•   События и делегаты
•   Асинхронные методы BeginXXXX и EndXXXX
•   async/await
•   Сторонние реализации
•   Да и зачем тут LINQ?
Типичные задачи
• Как обработать двойной клик?
• А тройной клик?
• Как проверять орфографию в
  словах, которые вводит пользователь в
  поле?
• Когда делать запросы в базу при
  реализации элемента управления «живой
  поиск»?
Pull-подход
• В .NET 4 появилось 2 новых интерфейса,
  реализующих pull-подход - IObservable<T> и
  IObserver<T>
Простой пример
• Push-коллекция




• Pull-коллекция
.NET Rx сборки
•   System.CoreEx
•   System.Interactive
•   System.Observable
•   System.Reactive
•   System.Threading
Реактивные расширения
• Представление асинхронных потоков
  данных как Observable
• Формирование запросов с помощью LINQ
• Параметризация конкурентных
  асинхронных потоков с помощью
  Schedulers
• Rx = Observables + LINQ + Schedulers
Операторы LINQ
•   Примитивы
•   Создание последовательностей
•   Конвертация
•   Комбинация
•   Математические операции
•   Временные операции
•   Фильтрация и выбор
•   Обработка исключений
•   Функциональные операции
•   Специальные операции
Примитивы
•   Never
•   Empty
•   Return
•   Throw
Создание последовательностей
•   Create
•   Generate
•   Defer
•   Range
Конвертация
•   FromAsyncPattern
•   FromEvent
•   FromEventPattern
•   ToObservable
•   ToEnumerable
Комбинация
•   Amb
•   Concat
•   StartWith
•   Merge
•   Repeat
•   Zip
Математические операции
•   Aggregate
•   Count
•   Min
•   Max
•   Sum
Временные операции
•   Delay
•   Interval
•   TimeInterval
•   Timestamp
•   Timeout
Фильтрация и выбор
•   Take
•   TakeUntil/TakeWhile
•   Select
•   SelectMany
•   Skip
•   SkipUntil/SkipWhile
Обработка исключений
•   Catch
•   Finally
•   Retry
•   OnErrorResumeNext
Функциональные операции
•   Let
•   Prune
•   Publish
•   Replay
Специальные операции
• Do
• Run
• Remotable
Многопоточность
• В каком потоке будет обрабатываться
  результирующая функция?
  – В текущем потоке
  – В новом потоке
  – В тредпуле
  – В потоке интерфейса
Schedulers
• Для управления конкурентными
  асинхронными потоками используются
  объекты, реализующие интерфейс
  IScheduler
• По умолчанию используется наиболее
  подходящий Scheduler
• Можно принудительно указать, какой
  Scheduler будет использоваться в
  конкретном случае
Scheduler по умолчанию
• Небольшое количество событий –
  ImmediateScheduler
• Большое или неопределенное количество
  событий – CurrentThreadScheduler
• При использовании таймеров -
  ThreadPoolScheduler
Использование Scheduler
• Используются статические свойства класса
  System.Reactive.Concurrency.Scheduler
• Указать Scheduler можно либо параметром
  в перегруженном методе оператора
  Observable.Timer(Timespan.FromSeconds(0.01), Sched
  uler.DispatcherScheduler).Subscribe(…);

• Либо с использованием специального
  оператора ObserveOn
  Observable.Timer(Timespan.FromSeconds(0.01))
    .ObserveOn(Scheduler.DispatcherScheduler)
    .Subscribe(…);
Пример запроса
Observable.FromEvent<TextChangedEventArgs>
 (searchTextBox, "TextChanged")
 .Select(e => ((TextBox)e.Sender).Text)
 .Where(text => text.Length > 2)
 .Do(s => searchResults.Opacity = 0.5)
 .Throttle(TimeSpan.FromMilliseconds(400))
 .ObserveOnDispatcher()
 .Do(s => Indicator.Visibility = Visibility.Visible)
 .SelectMany(txt => searchTwitter(txt))
 .Select(searchRes => ParseTwitterSearch(searchRes))
 .ObserveOnDispatcher()
 .Do(s => Indicator.Visibility = Visibility.Collapsed)
 .Do(s => searchResults.Opacity = 1)
 .Subscribe(tweets => searchResults.ItemsSource = tweets);
Где можно использовать?
•   .NET Framework 3.5 SP1
•   .NET Framework 4
•   Silverlight 4
•   Silverlight 5
•   Windows Phone 7
•   Windows Phone 7.1 “Mango”
•   .NET Framework 4.5 + WinRT (Experimental)
•   JavaScript
JavaScript
• Библиотека RxJS доступна в
  экспериментальной версии
• Логика работы повторяет логику Rx .NET
• Bridges – дополнительные конвертеры
Bridges
• FromDOMEvent

var canvas =
  document.getElementById("canvas");
var source =
  Rx.Observable.FromDOMEvent(canvas, "mousemove");

source.Subscribe(function(ev) {
  // Handle the mousemove event here
});
Bridges
• FromJQuery

Rx.Observable.FromJQuery($("div, span"), "click")
  .Subscribe(function(evt) {
    $("position").html("Mouse at " + evt.pageX +
                              ", " + evt.pageY);
  });
Bridges
• XmlHttpRequest
function searchWikipedia(term) {
  var url = "http://en.wikipedia.org/w/api.php" +
            "?action=opensearch&search=" + term +
            "&format=json";

    return Rx.Observable.XmlHttpRequest(url)
             .Select(function(result) {
                 var response = eval(result.responseText);
                 if (response.length == 2) return response[1];
                 else return [];
             });
}
Пример запроса
var input = $("#searchInput");
var words = input.ToObservable("keyup")
  .Select(function(_) { return input.val(); })
  .Throttle(500)
  .DistinctUntilChanged()
  .Select(function(term) { return search(term); })
  .Switch();
words.Subscribe(function(data) {
  $("#results").empty();
  $.each(data, function(_, value) {
    $("#results").append("<li>" + value + "</li>");
  }
});
На этом всё…
ВОПРОСЫ?
Полезные ссылки
• Reactive Extensions Developer Center
  http://msdn.microsoft.com/en-
  us/data/gg577609
• Reactive Framework Wiki
  http://rxwiki.wikidot.com/
• Rx Team Blog
  http://blogs.msdn.com/b/rxteam/
• Скачать Rx http://msdn.microsoft.com/en-
  us/data/gg577610
Следующая встреча
Спасибо за внимание!
    Если будут ещё вопросы – пишите!
    Сергей Звягин, Ingate Development
    • E-mail: bingofirst@gmail.com
    • Twitter: @Bingo87
    • Xbox: BingoRUS

Специально для GetDev.NET

Reactive Extensions

  • 1.
    Реактивные расширения для чайников Сергей Звягин Ingate Development Специально для GetDev.NET
  • 2.
    Реактивное программирование • Реактивноепрограммирование — парадигма программирования, ориентированная на потоки данных и распространение изменений. Это означает, что должна существовать возможность легко выражать статические и динамические потоки данных, а также то, что выполняемая модель должна автоматически распространять изменения сквозь поток данных. http://ru.wikipedia.org/wiki/Реактивное_программирование
  • 3.
    Push и Pull •Существует 2 подхода обработки последовательности данных • При push-подходе цель запрашивает у источника содержимое • При pull-подходе источник информирует цель о наличии данных
  • 4.
    Push-подход • Чтение изфайла • Суммирования элементов массива • Обработка выборки из БД
  • 5.
    Pull-подход • Обработка действий пользователя • Получение данных от веб-сервиса • Таймеры • Анимация пользовательского интерфейса
  • 6.
    Push-подход • Push-коллекции в.NET реализуются с использованием интерфейсов IEnumerable<T> и IEnumerator<T> • Это могут быть коллекции в памяти (списки, массивы), бесконечные последовательности (генераторы) или наборы данных с неизвестным заранее размером (выборка из БД) • LINQ позволяет быстро организовать работу с такими коллекциями
  • 7.
    Pull-подход • События и делегаты • Асинхронные методы BeginXXXX и EndXXXX • async/await • Сторонние реализации • Да и зачем тут LINQ?
  • 8.
    Типичные задачи • Какобработать двойной клик? • А тройной клик? • Как проверять орфографию в словах, которые вводит пользователь в поле? • Когда делать запросы в базу при реализации элемента управления «живой поиск»?
  • 9.
    Pull-подход • В .NET4 появилось 2 новых интерфейса, реализующих pull-подход - IObservable<T> и IObserver<T>
  • 10.
  • 11.
    .NET Rx сборки • System.CoreEx • System.Interactive • System.Observable • System.Reactive • System.Threading
  • 12.
    Реактивные расширения • Представлениеасинхронных потоков данных как Observable • Формирование запросов с помощью LINQ • Параметризация конкурентных асинхронных потоков с помощью Schedulers • Rx = Observables + LINQ + Schedulers
  • 13.
    Операторы LINQ • Примитивы • Создание последовательностей • Конвертация • Комбинация • Математические операции • Временные операции • Фильтрация и выбор • Обработка исключений • Функциональные операции • Специальные операции
  • 14.
    Примитивы • Never • Empty • Return • Throw
  • 15.
    Создание последовательностей • Create • Generate • Defer • Range
  • 16.
    Конвертация • FromAsyncPattern • FromEvent • FromEventPattern • ToObservable • ToEnumerable
  • 17.
    Комбинация • Amb • Concat • StartWith • Merge • Repeat • Zip
  • 18.
    Математические операции • Aggregate • Count • Min • Max • Sum
  • 19.
    Временные операции • Delay • Interval • TimeInterval • Timestamp • Timeout
  • 20.
    Фильтрация и выбор • Take • TakeUntil/TakeWhile • Select • SelectMany • Skip • SkipUntil/SkipWhile
  • 21.
    Обработка исключений • Catch • Finally • Retry • OnErrorResumeNext
  • 22.
    Функциональные операции • Let • Prune • Publish • Replay
  • 23.
  • 24.
    Многопоточность • В какомпотоке будет обрабатываться результирующая функция? – В текущем потоке – В новом потоке – В тредпуле – В потоке интерфейса
  • 25.
    Schedulers • Для управленияконкурентными асинхронными потоками используются объекты, реализующие интерфейс IScheduler • По умолчанию используется наиболее подходящий Scheduler • Можно принудительно указать, какой Scheduler будет использоваться в конкретном случае
  • 26.
    Scheduler по умолчанию •Небольшое количество событий – ImmediateScheduler • Большое или неопределенное количество событий – CurrentThreadScheduler • При использовании таймеров - ThreadPoolScheduler
  • 27.
    Использование Scheduler • Используютсястатические свойства класса System.Reactive.Concurrency.Scheduler • Указать Scheduler можно либо параметром в перегруженном методе оператора Observable.Timer(Timespan.FromSeconds(0.01), Sched uler.DispatcherScheduler).Subscribe(…); • Либо с использованием специального оператора ObserveOn Observable.Timer(Timespan.FromSeconds(0.01)) .ObserveOn(Scheduler.DispatcherScheduler) .Subscribe(…);
  • 28.
    Пример запроса Observable.FromEvent<TextChangedEventArgs> (searchTextBox,"TextChanged") .Select(e => ((TextBox)e.Sender).Text) .Where(text => text.Length > 2) .Do(s => searchResults.Opacity = 0.5) .Throttle(TimeSpan.FromMilliseconds(400)) .ObserveOnDispatcher() .Do(s => Indicator.Visibility = Visibility.Visible) .SelectMany(txt => searchTwitter(txt)) .Select(searchRes => ParseTwitterSearch(searchRes)) .ObserveOnDispatcher() .Do(s => Indicator.Visibility = Visibility.Collapsed) .Do(s => searchResults.Opacity = 1) .Subscribe(tweets => searchResults.ItemsSource = tweets);
  • 29.
    Где можно использовать? • .NET Framework 3.5 SP1 • .NET Framework 4 • Silverlight 4 • Silverlight 5 • Windows Phone 7 • Windows Phone 7.1 “Mango” • .NET Framework 4.5 + WinRT (Experimental) • JavaScript
  • 30.
    JavaScript • Библиотека RxJSдоступна в экспериментальной версии • Логика работы повторяет логику Rx .NET • Bridges – дополнительные конвертеры
  • 31.
    Bridges • FromDOMEvent var canvas= document.getElementById("canvas"); var source = Rx.Observable.FromDOMEvent(canvas, "mousemove"); source.Subscribe(function(ev) { // Handle the mousemove event here });
  • 32.
    Bridges • FromJQuery Rx.Observable.FromJQuery($("div, span"),"click") .Subscribe(function(evt) { $("position").html("Mouse at " + evt.pageX + ", " + evt.pageY); });
  • 33.
    Bridges • XmlHttpRequest function searchWikipedia(term){ var url = "http://en.wikipedia.org/w/api.php" + "?action=opensearch&search=" + term + "&format=json"; return Rx.Observable.XmlHttpRequest(url) .Select(function(result) { var response = eval(result.responseText); if (response.length == 2) return response[1]; else return []; }); }
  • 34.
    Пример запроса var input= $("#searchInput"); var words = input.ToObservable("keyup") .Select(function(_) { return input.val(); }) .Throttle(500) .DistinctUntilChanged() .Select(function(term) { return search(term); }) .Switch(); words.Subscribe(function(data) { $("#results").empty(); $.each(data, function(_, value) { $("#results").append("<li>" + value + "</li>"); } });
  • 35.
  • 36.
    Полезные ссылки • ReactiveExtensions Developer Center http://msdn.microsoft.com/en- us/data/gg577609 • Reactive Framework Wiki http://rxwiki.wikidot.com/ • Rx Team Blog http://blogs.msdn.com/b/rxteam/ • Скачать Rx http://msdn.microsoft.com/en- us/data/gg577610
  • 37.
  • 38.
    Спасибо за внимание! Если будут ещё вопросы – пишите! Сергей Звягин, Ingate Development • E-mail: bingofirst@gmail.com • Twitter: @Bingo87 • Xbox: BingoRUS Специально для GetDev.NET