Reactive Extensions
Сергей Тепляков
STeplyakov@luxoft.com
О Вашем инструкторе


 Сергей Тепляков
 Visual C# MVP, RSDN Team member
 Sergey.Teplyakov@gmail.com
 SergeyTeplyakov.blogspot.com




                                    1-2
Необходимая подготовка
Слушатели должны:

 Быть знакомы с основами языка C#
  и платформы .Net
 Обладать базовыми знаниями
  многопоточности
 Быть знакомы с LINQ (Language
  Integrated Query)


                                     1-4
Roadmap

   Введение в реактивные расширения
   Дуализм интерфейсов
   Основы Rx
   Observable sequences
   Events и Observables
   Observables и асинхронные операции
   Concurrency
   Новости из Редмонта
                                         1-5
Интерактивная и реактивная
модель
Реактивное программирование

Парадигма программирования, ориентированная на потоки
данных и распространение изменений. Это означает, что
должна    существовать   возможность   легко    выражать
статические и динамические потоки данных, а также то, что
выполняемая модель должна автоматически распространять
изменения сквозь поток данных.

http://ru.wikipedia.org/
/wiki/Реактивное_программирование
Реактивная модель

"Принцип Голливуда" – "Не звоните нам, мы сами вам
позвоним"

(Hollywood Principle - Don't call us, we'll call you)
Rx - это

1. набор классов, представляющих собой асинхронный
поток данных
2. набор операторов, предназначенных для
манипуляции этими данными
3. набор классов для управления многопоточностью

Rx = Observables + LINQ + Schedulers
Зачем все это нужно?
                              GPS


              RSS   feeds




  Social
  media




                            Server management
Интерфейс IEnumerable

Pull-based последовательности представлены
интерфейсом IEnumerable. Это -
 коллекции в памяти (списки, вектора и
  т.д.)
 бесконечные последовательности
  (генераторы)
 xml-данные
 результаты запроса к БД
Интерфейс IEnumerable

public interface IEnumerable<out T>
{
    IEnumerator<T> GetEnumerator();
}                                     Ковариантность из
                                          .NET 4.0

public interface IEnumerator<out T> : IDisposable
{                            Блокирующая
    bool MoveNext();           операция
    T Current { get; }
    void Reset();
}
Упрощение интерфейса
IEnumerator

public interface IEnumerator<out T> : IDisposable
{
  (T | void | Exception) GetNext();
}




    T – следующий элемент
    void – окончание
    последовательности
    Exception – ошибка
Интерфейс IObservable

public interface IObservable<out T>
{
    IDisposable Subscribe(IObserver<T> observer);
}

public interface IObserver<in T>
{
    void OnNext(T value);
    void OnError(Exception error);
    void OnCompleted();
}
Pull vs Push
Pull vs Push
Простые последовательности

                             OnComplete

Observable.Empty<int>();                  new int[] {};

                              OnNext

Observable.Return(42);                    new int[] {42};

                              OnError
                                                  Итератор,
Observable.Throw<int>(ex);                      генерирующий
                                                 исключение
                                            Итератор, который не
Observable.Never<int>();                        возвращает
                                                управление
Методы Range

Observable.Range(0, 3);

 OnNext(0)    OnNext(1)   OnNext(2)




Enumerable.Range(0, 3);

  yield 0      yield 1     yield 2
Циклы for

var 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);
                                }
   });
Контракт «реактивных»
последовательностей

 Grammar: OnNext* [OnCompleted | OnError]
 Методы наблюдателя вызываются
  последовательно
Упрощение работы с
интерфейсом IObserver
var xs = Observable.Range(0, 10);
1. Только OnNext:
xs.Subscribe(/*OnNext(int)*/x => Console.WriteLine(x));
2. OnNext и OnCompleted
xs.Subscribe(
    /*OnNext(int)*/x => Console.WriteLine(x),
    /*OnComplete*/() => Console.WriteLine("Completed"));
3. OnNext и OnError
xs.Subscribe(
    /*OnNext(int)*/x => Console.WriteLine(x),
    /*OnError(Exception)*/e => Console.WriteLine("Error: {0}", e));
4. OnNext, OnError и OnCompleted
xs.Subscribe(
    /*OnNext(int)*/x => Console.WriteLine(x),
    /*OnError(Exception)*/e => Console.WriteLine("Error: {0}", e),
    /*OnCompleted*/() => Console.WriteLine("Completed"));
Demo
События в .NET

 Объявление
    event Action<int> E;
 Публикация
    E(42);
 Подписка
    E += x => Console.WriteLine(x);
Rx

 Объявление
     ISubject<int> S = new Subject<int>();
 Публикация
     S.OnNext(42);
 Подписка
     S.Subscribe(x => Console.WriteLine(x));
Events vs Observables

class 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);
    }                                           }
}                                           }
Отписка от событий

 Events
static event Action<string> E;

//E += x => Console.WriteLine(x);
Action<string> action = x => Console.WriteLine(x);
E += action;
E -= action;

 Observables
static ISubject<int> S = new Subject<int>();

var token = S.Subscribe(x => Console.WriteLine(x));
token.Dispose();
«События» первого класса

Объект называют «объектом первого класса» когда он:
 может быть сохранен в переменной
 может быть передан в функцию как параметр
 может быть возвращен из функции как результат
 может быть создан во время выполнения программы
 внутренне самоидентифицируем (независим от
   именования)

http://ru.wikipedia.org/wiki/Объект_первого_класса
«События» первого класса

// Сохранение в переменной
IObservable<string> textChanged = …;

// Передача в качестве параметра
void ProcessRequests(IObservable<string> input) {…}

// Возвращение в качестве результата
IObservable<int> QueryServer() {…}
Возможности наблюдаемых
последовательностей
                                        Преобразование события в поток
                                                объектов Point
IObservable<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();
Demo
Асинхронные операции
Classical Async Pattern
FileStream 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);                    Сложность обработки ошибок, а
                                               также чтения и сопровождения
                                                           кода
FromAsyncPattern

static 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));
Tasks vs FromAsyncPattern

 Задачи (Tasks) – это унифицированный
  способ представления Single value
  asynchrony в .Net Framework
 Observables – Multi value asynchrony
 Существует простой способ
  преобразования Tasks -> Observables
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"));
        }

   }
Чем Rx не является

 Rx не заменяет существующей «асинхронности»:
      .NET все еще незаменимы
      Асинхронные методы все так же применимы в библиотеках
      Задачи представляют собой single value asynchrony
      Существуют и другие асинхронные источники, как SSIS,
       PowerShell, etc
 Но rx…
    Унифицирует работу
    Предоставляет возможность композиции
    Предоставляет обобщенные операторы
 Так что rx – это …
    Мост!
Demo
Управление многопоточность

 Управление многопоточностью
  осуществляется с помощью
  интерфейса IScheduler
var xs = Observable.Range(0, 10, Scheduler.ThreadPool);

xs.Subscribe(x => Console.WriteLine(x));

                                     Параметризация с помощью
  Будет исполняться в контексте
                                  IScheduler доступна в большинстве
          планировщика
                                               операций
Синхронизация

   Обновление пользовательского интерфейса
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;
});




 Использование ObserveOn
xs.ObserveOn(frm).Subscribe(x =>
{
    Thread.Sleep(1000);                      IScheduler поддерживает разные
    lbl.Text = "Result is " + x;                контексты синхронизации
});
Demo
Что мы изучили?

   Введение в реактивные расширения
   Дуализм интерфейсов
   Основы Rx
   Observable sequences
   Events и Observables
   Observables и асинхронные операции
   Concurrency

                                         1-40
Experimental vs Stable

 Две версии библиотеки Reactive
  Extensions:
   Stable
   Experimental
 Interactive Extensions
Где взять?

 NuGet
 Web - http://msdn.microsoft.com/en-
  us/data/gg577610
 Can’t find? Use google
Дополнительные ссылки

   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
Roslyn CTP is awailable!




http://msdn.microsoft.com/ru-ru/roslyn
Вопросы?

Reactive extensions

  • 1.
  • 2.
    О Вашем инструкторе Сергей Тепляков  Visual C# MVP, RSDN Team member  Sergey.Teplyakov@gmail.com  SergeyTeplyakov.blogspot.com 1-2
  • 3.
    Необходимая подготовка Слушатели должны: Быть знакомы с основами языка C# и платформы .Net  Обладать базовыми знаниями многопоточности  Быть знакомы с LINQ (Language Integrated Query) 1-4
  • 4.
    Roadmap  Введение в реактивные расширения  Дуализм интерфейсов  Основы Rx  Observable sequences  Events и Observables  Observables и асинхронные операции  Concurrency  Новости из Редмонта 1-5
  • 5.
  • 6.
    Реактивное программирование Парадигма программирования,ориентированная на потоки данных и распространение изменений. Это означает, что должна существовать возможность легко выражать статические и динамические потоки данных, а также то, что выполняемая модель должна автоматически распространять изменения сквозь поток данных. http://ru.wikipedia.org/ /wiki/Реактивное_программирование
  • 7.
    Реактивная модель "Принцип Голливуда"– "Не звоните нам, мы сами вам позвоним" (Hollywood Principle - Don't call us, we'll call you)
  • 8.
    Rx - это 1.набор классов, представляющих собой асинхронный поток данных 2. набор операторов, предназначенных для манипуляции этими данными 3. набор классов для управления многопоточностью Rx = Observables + LINQ + Schedulers
  • 9.
    Зачем все этонужно? GPS RSS feeds Social media Server management
  • 10.
    Интерфейс IEnumerable Pull-based последовательностипредставлены интерфейсом IEnumerable. Это -  коллекции в памяти (списки, вектора и т.д.)  бесконечные последовательности (генераторы)  xml-данные  результаты запроса к БД
  • 11.
    Интерфейс IEnumerable public interfaceIEnumerable<out T> { IEnumerator<T> GetEnumerator(); } Ковариантность из .NET 4.0 public interface IEnumerator<out T> : IDisposable { Блокирующая bool MoveNext(); операция T Current { get; } void Reset(); }
  • 12.
    Упрощение интерфейса IEnumerator public interfaceIEnumerator<out T> : IDisposable { (T | void | Exception) GetNext(); } T – следующий элемент void – окончание последовательности Exception – ошибка
  • 13.
    Интерфейс IObservable public interfaceIObservable<out T> { IDisposable Subscribe(IObserver<T> observer); } public interface IObserver<in T> { void OnNext(T value); void OnError(Exception error); void OnCompleted(); }
  • 14.
  • 15.
  • 16.
    Простые последовательности OnComplete Observable.Empty<int>(); new int[] {}; OnNext Observable.Return(42); new int[] {42}; OnError Итератор, Observable.Throw<int>(ex); генерирующий исключение Итератор, который не Observable.Never<int>(); возвращает управление
  • 17.
    Методы Range Observable.Range(0, 3); OnNext(0) OnNext(1) OnNext(2) Enumerable.Range(0, 3); yield 0 yield 1 yield 2
  • 18.
    Циклы for var 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.
    Контракт «реактивных» последовательностей  Grammar:OnNext* [OnCompleted | OnError]  Методы наблюдателя вызываются последовательно
  • 20.
    Упрощение работы с интерфейсомIObserver var xs = Observable.Range(0, 10); 1. Только OnNext: xs.Subscribe(/*OnNext(int)*/x => Console.WriteLine(x)); 2. OnNext и OnCompleted xs.Subscribe( /*OnNext(int)*/x => Console.WriteLine(x), /*OnComplete*/() => Console.WriteLine("Completed")); 3. OnNext и OnError xs.Subscribe( /*OnNext(int)*/x => Console.WriteLine(x), /*OnError(Exception)*/e => Console.WriteLine("Error: {0}", e)); 4. OnNext, OnError и OnCompleted xs.Subscribe( /*OnNext(int)*/x => Console.WriteLine(x), /*OnError(Exception)*/e => Console.WriteLine("Error: {0}", e), /*OnCompleted*/() => Console.WriteLine("Completed"));
  • 21.
  • 22.
    События в .NET Объявление event Action<int> E;  Публикация E(42);  Подписка E += x => Console.WriteLine(x);
  • 23.
    Rx  Объявление ISubject<int> S = new Subject<int>();  Публикация S.OnNext(42);  Подписка S.Subscribe(x => Console.WriteLine(x));
  • 24.
    Events vs Observables classProgram { 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.
    Отписка от событий Events static event Action<string> E; //E += x => Console.WriteLine(x); Action<string> action = x => Console.WriteLine(x); E += action; E -= action;  Observables static ISubject<int> S = new Subject<int>(); var token = S.Subscribe(x => Console.WriteLine(x)); token.Dispose();
  • 26.
    «События» первого класса Объектназывают «объектом первого класса» когда он:  может быть сохранен в переменной  может быть передан в функцию как параметр  может быть возвращен из функции как результат  может быть создан во время выполнения программы  внутренне самоидентифицируем (независим от именования) http://ru.wikipedia.org/wiki/Объект_первого_класса
  • 27.
    «События» первого класса //Сохранение в переменной IObservable<string> textChanged = …; // Передача в качестве параметра void ProcessRequests(IObservable<string> input) {…} // Возвращение в качестве результата IObservable<int> QueryServer() {…}
  • 28.
    Возможности наблюдаемых последовательностей Преобразование события в поток объектов Point IObservable<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.
  • 30.
    Асинхронные операции Classical AsyncPattern FileStream 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.
    FromAsyncPattern static int LongRunningFunc(strings) { 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.
    Tasks vs FromAsyncPattern Задачи (Tasks) – это унифицированный способ представления Single value asynchrony в .Net Framework  Observables – Multi value asynchrony  Существует простой способ преобразования Tasks -> Observables
  • 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.
    Чем Rx неявляется  Rx не заменяет существующей «асинхронности»:  .NET все еще незаменимы  Асинхронные методы все так же применимы в библиотеках  Задачи представляют собой single value asynchrony  Существуют и другие асинхронные источники, как SSIS, PowerShell, etc  Но rx…  Унифицирует работу  Предоставляет возможность композиции  Предоставляет обобщенные операторы  Так что rx – это …  Мост!
  • 35.
  • 36.
    Управление многопоточность  Управлениемногопоточностью осуществляется с помощью интерфейса IScheduler var xs = Observable.Range(0, 10, Scheduler.ThreadPool); xs.Subscribe(x => Console.WriteLine(x)); Параметризация с помощью Будет исполняться в контексте IScheduler доступна в большинстве планировщика операций
  • 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; });  Использование ObserveOn xs.ObserveOn(frm).Subscribe(x => { Thread.Sleep(1000); IScheduler поддерживает разные lbl.Text = "Result is " + x; контексты синхронизации });
  • 38.
  • 39.
    Что мы изучили?  Введение в реактивные расширения  Дуализм интерфейсов  Основы Rx  Observable sequences  Events и Observables  Observables и асинхронные операции  Concurrency 1-40
  • 40.
    Experimental vs Stable Две версии библиотеки Reactive Extensions:  Stable  Experimental  Interactive Extensions
  • 41.
    Где взять?  NuGet Web - http://msdn.microsoft.com/en- us/data/gg577610  Can’t find? Use google
  • 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.
    Roslyn CTP isawailable! http://msdn.microsoft.com/ru-ru/roslyn
  • 44.

Editor's Notes

  • #10 Обращаю внимание, что под «управлением» подразумевается не синхронизация, а «параметризация» определенных методов дополнительными объектами, которые знают, в каком контексте необходимо выполнить определенную операцию. Наиболее типичным примерам такого управления является использование специализированных планировщиков, которые будут вызывать методы наблюдателя в контексте синхронизации.
  • #11 Rx - это клей, &quot;склеивающий&quot; разнородныеасинхронныеисточникиданных.
  • #13 Эта пара интерфейс как раз и представляют ту самую 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&lt;Derived&gt; и IEnumerable&lt;Base&gt;:IEnumerable&lt;Derived&gt; d = new List&lt;Derived&gt;(); IEnumerable&lt;Base&gt; b = d;
  • #16 Барточеньприкольновыразился, когдасказал, чтозачастуюпаттерны в бандечетырехсгруппированывместе по схожести. Новотсхожестьмеждуитератором и наблюдателемникак не обозначена. В целом, этосвязано с тем, что push-basedколлекцииявляютсялишьчастнымслучаемнаблюдателя, и этотпаттернможетприменяться и в других контекстах. Но, тем не менее, еслипосмотретьподэтимуглом, то симетриямеждуэтимидвумяпаттернамиприсутствует.
  • #18 Первые три слайда показывают семантическую схожесть (или проводят аналогии) между некоторыми встроенными и простыми наблюдаемыми последовательностями и обычными структурами данных и последовательностями.
  • #20 Но прежде чем переходить к небольшой демонстрации, давайте рассмотрим еще несколько важных тем.Во-первых, нам нужно рассмотреть упрощенную версию метода Subscribe, который вместо того, чтобы принимать интерфейс IObserver принимает лямбда-выражение. Кроме того, нам нужно рассмотреть процесс отписки от событий, чтобы рассматриваемые пример были более понятными.
  • #21 Аналогично тому, как вы не можете получить следующий элемент последовательности, пока вы не получили предыдущий, асинхронные последовательности также предоставляют подобные гарантии. (Да, кстати, вы можете добиться этого, но для этого придется попотеть). Точно также, правильная реактивная библиотека, которая следует определенным рекомендациям (существует специальный документ, который называется Rx Design Guidelines) не должна отправлять одному и тому же наблюдателю следующие элемент, пока не завершилась обработка предыдущего элемента.
  • #22 Тут словам можно сказать, что поскольку у нас нет, как в Джаве анонимной реализации интерфейсов, то мы можем это эмулировать с помощью методов расширения
  • #23 Запустить голый проект в Visual Studio 2010 с добавленными ссылками на Rx и показать несколько простых и примитивных примеров. В частности, показать, что при добавлении соответствующей using директивы мы получим множество методов расширения, которые позволят нам использовать LINQ во всей красе.Затем, дать пример, который генерирует последовательность данных и немного с ней поиграться.Добавить простой метод Generateс параметром TimeSpan, показать, что основной поток все еще не заблокирован.Потом запустить Generate с random-ом и поиграться еще. Добавить DistinctUntilChanged();, а потом Buffer с печатью всех элементов, а потом с суммой.
  • #25 Здесь нужно обязательно сказать и, возможно даже показать сложность с отпиской от события. Ведь для нормальной отписки от события
  • #27 Еще одним недостатком событий, о котором следует упомянуть – это отсутствие композиции. Мы не можем отфильтровать данные одного события и сделать из него другое. Для этого нужно добавить совершенно новое событие. А если нам нужно несколько способов манипулирования (фильтрации, получения проекции), то сложность решения резко возрастает.
  • #31 Запустить VS2010 и попробовать отфильтровать события пользовательского интерфейса и показать, что из этого получается.
  • #32 Фраза о том, что Task – это single value asynchrony etc
  • #36 Очень важно сказать, что RX строятсяon top of existing abstractions but they’re not going to replace them. Остается множество мест, где события нужно использовать напрямую, не оборачивая их ни в какие последовательности. Мы кликнули на форме и получили событие загрузки формы, мы никогда не получим множество событий загрузки формы, которые мы хотели бы композировать каким-то хитрым образом. Если нам нужно обработать событие клика мышки, то опять же, нет никакого смысла добавлять что-либо.Точно так же, все существующие примитивы в .NET Framework остаются такими же ценными, какими они были вчера. Никто не собирается изменять низкоуровневый код, который прекрасно работает и заточен лишь для одной цели. Но теперь, работая с ним его легко можно обернуть в более высокоуровневые примитивы и работать с ним с более высокого уровня абстракции.
  • #37 Примеры, посвященные асинхронности.
  • #38 Описать и рассказать об интерфейсе IScheduler, который инкапсулирует в себе вопросы асинхронности и управления ею.По умолчанию используется скеджулер, который называется Immediate, т.е. который не делает никакой многопоточности. И это разумно, поскольку многопоточность не бесплатна. Но практически все операции, типа Return, Range и т.д. принимают дополнительный параметр (т.е. содержат соответствующую перегрузку), который принимает интерфейс Ischeduler.В большинстве случаев об этом параметре можно не думать, поскольку решение по умолчанию нам подходит. Так, например, метод Generate, который принимает еще и TimeSpan по умолчанию использует ThreadPool, поскольку использование текущего потока сделает этот метод бесполезным.
  • #40 А вот здесь показать, как упадет тот же самый пример без асинхронности, но будет жить, когда мы ее добавим контекст синхронизации!
  • #47 Пример из выступления Вейеса!