SlideShare a Scribd company logo
1 of 12
Высокоуровневая обработка
событий
С помощью библиотеки
Reactive Extensions
Минусы событий .NET
•Требует указания конкретного делегата
•Затрудняет использование лямбд
•Провоцирует утечки ресурсов
Отписка
• Обработка событий с учетом временных зависимостей
крайне затрудненаУчет времени
•Для потока данных есть LINQ, а для потока событий это
невозможно – событие не значение первого классаКомпозиция
•В каком контексте будет выполнятся обработчик – зависит от
событияСинхронность
События как интерфейсы
•Это источник событий, аналог event
•Единственный метод – подписка : IDisposable Subscribe( IObserver<T> observer )
•Отписка, если нужна – простым вызовом Dispose
IObservable<T>
•Это приемник событий, аналог IEventHandler из нашего Delphi-фреймворка
•Основной метод – обработка события void OnNext(T value )
•Уведомление, что событий больше не будет void OnCompleted()
• Уведомление, что об ошибке в источнике void OnError(Exception error )
IObserver<T>
•Событие как интерфейс - значение первого класса
•Можно использовать с using
•Знакомый классический паттерн банды четырех после нашего фреймворка Delphi и
Java
Плюсы
•Методы Subscribe и Dispose должны быть потокобезопасными
•Наблюдатель не должен выбрасывать исключения из своих реализаций методов
•Не рекомендуется отменять регистрацию в реализации Subscribe
•Не рекомендуется подписывать одного наблюдателя на несколько потоков событий
Требования
Да будет LINQ!
• Поток событий – аналог потока данных
• GetEnumerator = Subscribe
• Current = OnNext + OnException
• !MoveNext = OnComplete
• Dispose = subscribe.Dispose
IEnumerable
IObservable
• LINQ для событий возможен, как и для любых значений первого класса
• По семантике LINQ для потоков событий похож на LINQ для коллекций
• Только в самом фреймворке ничего такого нет
LINQ2events
• Готовые универсальные реализации IObservable и IObserver
• При подписке можно просто указывать обработчики, а также токен отмены
• Реализация LINQ для IObservable
• Поддержка асинхронности, параллелизма и конвертации в привычные
сущности (последовательности, события, задачи, асинхронные вызовы) и
обратно
Reactive
Extensions
Особенности потоков событий
•Для событий в одном потоке задано отношение полного порядка
– одно событие раньше, другое - позже
•Новое событие не будет передано подписчикам до окончания
обработки предыдущего
Упорядоченность
•У события есть время возникновения
•ToInterval добавляет время между событиями
•Throttle исключает частые события
•Множество других фильтров и комбинаторов с учетом времени
Темпоральность
•Возникновение события в общем случае не привязано к
текущему контексту
•Поток событий – аналог асинхронного вызова для множества
возвращаемых результатов
Асинхронность
Генераторы событий
Статические методы Observable
•Return – ровно одно событие
•Empty – ни одного события, сразу конец
•Throw – сразу ошибка
•Never – абсолютная тишина, ни одного вызова
Примитивные
•Range – аналогично как и для IEnumerable
•Generate – аналог цикла forПоследовательные
•Timer – одно событие в указанное время или через
указанный временной интервал
•Interval – события с указанным временным интервалом
между ними
Временные
Горячие и холодные источники
• Генерируют события только при подписке
• Выдают каждому подписчику все сообщения с самого начала
• Пример – ранее приведенные генераторы
Холодные
• Генерируют события независимо от наличия подписчиков
• Выдают подписчикам события только в период подписки, разделяя
каждое сообщение между всеми подписчиками
• Пример – события от клавиатуры и мыши
Горячие
• Метод расширения Publish возвращает горячий источник, позволяя
разделять одну подписку на холодный между несколькими
наблюдателямиРазогрев
Планировщики
• Sheduler.Immediate – немедленное выполнение без планирования
• Scheduler.CurrentThread – c контролем deadlock’овОднопоточные
• Scheduler.NewThread – выполнение в новом потоке
• Scheduler.TaskPool – выполнение в TPL.Task
• Scheduler.ThreadPool – выполнение в пуле потоков
Многопоточные
• DispatcherScheduler – выполнение в потоке UI для WPF/Silverlight
• ControlScheduler – то же для WinFormsUI
• Автоматический – ничего указывать не надо, будет выбран наиболее
подходящий
• В LINQ – можно явно указать для последовательности с помощью метода
ObserveOn
Выбор
Мосты
• Методы ToObservale и ToEnumerable
• Все стандартные ToXXX методы LINQ
Последовательности и
коллекции
• Метод FromEventPattern
• Можно указать методы для подписки и отписки
• Для событий по шаблону EventHandler можно указать имя (найдется с
помощью отражения)
События
• Метод FromAsyncPattern
• Превращает вызов в поток событий с одним элементом - результатомАсинхронные вызовы
• Метод расширения для задачи ToObservable
• Метод расширения для источника ToTask (вернет последнее значение)
• Задача от источника событий отличается только количеством результатов
Задачи
Drag & Drop
• var mousedown = from evt in
Observable.FromEvent<MouseButtonEventArgs>(this, "MouseDown")
select evt.EventArgs.GetPosition(this);
Нажатия
• var mouseup = from evt in
Observable.FromEvent<MouseButtonEventArgs>(this, "MouseUp" )
select evt.EventArgs.GetPosition(this);
Отпускания
• var mousemove = from evt in
Observable.FromEvent<MouseEventArgs>(this, "MouseMove" )
select evt.EventArgs.GetPosition(this);
Перемещения
• var q = from start in mousedown from pos in
mousemove.StartWith(start).TakeUntil(mouseup)
select pos;
Перетаскивание
• q.ObserveOnDispatcher().Subscribe(
value => textBlock.Text = value.ToString());Обновление UI
Асинхронный вызов
• Используется метод расширения using, гарантирующий
вызов Dispose после завершения потока событий
• Observable.Using(() => new WCFServiceClient()
Автоочистка
ресурсов
• , client => Observable.
FromAsyncPattern<RequestType, ResponseType>(
client.BeginWCFMethod,
client.EndWCFMethod)(request))
Конвертация
вызова
• .Subscribe(
response => response.List.ForEach(WriteOutBusiness),
ex => Console.WriteLine("Error = " + ex.Message),
() => Console.WriteLine("Completed."));
Обработка
результата
Источники вдохновения
1. Шаблон разработки Observer
2. Композиционный стиль программирования с
Reactive Extensions (презентация)
3. Библиотека реактивных расширений (видео)
4. Creating and Subscribing to Simple Observable
Sequences
5. Jesse Liberty – Reactive
6. “Реактивные расширения” и асинхронные
операции

More Related Content

Similar to Высокоуровневая обработка событий

Асинхронные вызовы в .NET
Асинхронные вызовы в .NETАсинхронные вызовы в .NET
Асинхронные вызовы в .NETBonart
 
Reactive Extensions
Reactive ExtensionsReactive Extensions
Reactive ExtensionsGetDev.NET
 
Svitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak OleksiiSvitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak OleksiiSvitla Systems Inc.
 
Java осень 2013 лекция 6
Java осень 2013 лекция 6Java осень 2013 лекция 6
Java осень 2013 лекция 6Technopark
 
PHP libevent Daemons. A high performance and reliable solution. Practical exp...
PHP libevent Daemons. A high performance and reliable solution. Practical exp...PHP libevent Daemons. A high performance and reliable solution. Practical exp...
PHP libevent Daemons. A high performance and reliable solution. Practical exp...Arvids Godjuks
 
Android - 11 - Multithreading
Android - 11 - MultithreadingAndroid - 11 - Multithreading
Android - 11 - MultithreadingNoveo
 
Android осень 2013 лекция 3
Android осень 2013 лекция 3Android осень 2013 лекция 3
Android осень 2013 лекция 3Technopark
 
Процессы и потоки
Процессы и потокиПроцессы и потоки
Процессы и потокиEvgeniy Mironov
 
Высокоуровневый параллелизм
Высокоуровневый параллелизмВысокоуровневый параллелизм
Высокоуровневый параллелизмBonart
 
Асинхронность и сопрограммы
Асинхронность и сопрограммыАсинхронность и сопрограммы
Асинхронность и сопрограммыPlatonov Sergey
 
Операционные системы 2015, лекция № 4
Операционные системы 2015, лекция № 4Операционные системы 2015, лекция № 4
Операционные системы 2015, лекция № 4Aleksey Bragin
 
Лекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILЛекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILRoman Brovko
 
C# Desktop. Занятие 15.
C# Desktop. Занятие 15.C# Desktop. Занятие 15.
C# Desktop. Занятие 15.Igor Shkulipa
 
Reactive programming для успеха вашего стартапа
Reactive programming для успеха вашего стартапаReactive programming для успеха вашего стартапа
Reactive programming для успеха вашего стартапаVitebsk DSC
 
Управление ресурсами в Linux и OpenVZ
Управление ресурсами в Linux и OpenVZ Управление ресурсами в Linux и OpenVZ
Управление ресурсами в Linux и OpenVZ OpenVZ
 

Similar to Высокоуровневая обработка событий (20)

Асинхронные вызовы в .NET
Асинхронные вызовы в .NETАсинхронные вызовы в .NET
Асинхронные вызовы в .NET
 
Working with .NET Threads
Working with .NET ThreadsWorking with .NET Threads
Working with .NET Threads
 
Reactive Extensions
Reactive ExtensionsReactive Extensions
Reactive Extensions
 
Svitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak OleksiiSvitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak Oleksii
 
Event Machine
Event MachineEvent Machine
Event Machine
 
Async
AsyncAsync
Async
 
Luxoft async.net
Luxoft async.netLuxoft async.net
Luxoft async.net
 
Java осень 2013 лекция 6
Java осень 2013 лекция 6Java осень 2013 лекция 6
Java осень 2013 лекция 6
 
PHP libevent Daemons. A high performance and reliable solution. Practical exp...
PHP libevent Daemons. A high performance and reliable solution. Practical exp...PHP libevent Daemons. A high performance and reliable solution. Practical exp...
PHP libevent Daemons. A high performance and reliable solution. Practical exp...
 
Async Python
Async PythonAsync Python
Async Python
 
Android - 11 - Multithreading
Android - 11 - MultithreadingAndroid - 11 - Multithreading
Android - 11 - Multithreading
 
Android осень 2013 лекция 3
Android осень 2013 лекция 3Android осень 2013 лекция 3
Android осень 2013 лекция 3
 
Процессы и потоки
Процессы и потокиПроцессы и потоки
Процессы и потоки
 
Высокоуровневый параллелизм
Высокоуровневый параллелизмВысокоуровневый параллелизм
Высокоуровневый параллелизм
 
Асинхронность и сопрограммы
Асинхронность и сопрограммыАсинхронность и сопрограммы
Асинхронность и сопрограммы
 
Операционные системы 2015, лекция № 4
Операционные системы 2015, лекция № 4Операционные системы 2015, лекция № 4
Операционные системы 2015, лекция № 4
 
Лекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILЛекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GIL
 
C# Desktop. Занятие 15.
C# Desktop. Занятие 15.C# Desktop. Занятие 15.
C# Desktop. Занятие 15.
 
Reactive programming для успеха вашего стартапа
Reactive programming для успеха вашего стартапаReactive programming для успеха вашего стартапа
Reactive programming для успеха вашего стартапа
 
Управление ресурсами в Linux и OpenVZ
Управление ресурсами в Linux и OpenVZ Управление ресурсами в Linux и OpenVZ
Управление ресурсами в Linux и OpenVZ
 

Высокоуровневая обработка событий

  • 2. Минусы событий .NET •Требует указания конкретного делегата •Затрудняет использование лямбд •Провоцирует утечки ресурсов Отписка • Обработка событий с учетом временных зависимостей крайне затрудненаУчет времени •Для потока данных есть LINQ, а для потока событий это невозможно – событие не значение первого классаКомпозиция •В каком контексте будет выполнятся обработчик – зависит от событияСинхронность
  • 3. События как интерфейсы •Это источник событий, аналог event •Единственный метод – подписка : IDisposable Subscribe( IObserver<T> observer ) •Отписка, если нужна – простым вызовом Dispose IObservable<T> •Это приемник событий, аналог IEventHandler из нашего Delphi-фреймворка •Основной метод – обработка события void OnNext(T value ) •Уведомление, что событий больше не будет void OnCompleted() • Уведомление, что об ошибке в источнике void OnError(Exception error ) IObserver<T> •Событие как интерфейс - значение первого класса •Можно использовать с using •Знакомый классический паттерн банды четырех после нашего фреймворка Delphi и Java Плюсы •Методы Subscribe и Dispose должны быть потокобезопасными •Наблюдатель не должен выбрасывать исключения из своих реализаций методов •Не рекомендуется отменять регистрацию в реализации Subscribe •Не рекомендуется подписывать одного наблюдателя на несколько потоков событий Требования
  • 4. Да будет LINQ! • Поток событий – аналог потока данных • GetEnumerator = Subscribe • Current = OnNext + OnException • !MoveNext = OnComplete • Dispose = subscribe.Dispose IEnumerable IObservable • LINQ для событий возможен, как и для любых значений первого класса • По семантике LINQ для потоков событий похож на LINQ для коллекций • Только в самом фреймворке ничего такого нет LINQ2events • Готовые универсальные реализации IObservable и IObserver • При подписке можно просто указывать обработчики, а также токен отмены • Реализация LINQ для IObservable • Поддержка асинхронности, параллелизма и конвертации в привычные сущности (последовательности, события, задачи, асинхронные вызовы) и обратно Reactive Extensions
  • 5. Особенности потоков событий •Для событий в одном потоке задано отношение полного порядка – одно событие раньше, другое - позже •Новое событие не будет передано подписчикам до окончания обработки предыдущего Упорядоченность •У события есть время возникновения •ToInterval добавляет время между событиями •Throttle исключает частые события •Множество других фильтров и комбинаторов с учетом времени Темпоральность •Возникновение события в общем случае не привязано к текущему контексту •Поток событий – аналог асинхронного вызова для множества возвращаемых результатов Асинхронность
  • 6. Генераторы событий Статические методы Observable •Return – ровно одно событие •Empty – ни одного события, сразу конец •Throw – сразу ошибка •Never – абсолютная тишина, ни одного вызова Примитивные •Range – аналогично как и для IEnumerable •Generate – аналог цикла forПоследовательные •Timer – одно событие в указанное время или через указанный временной интервал •Interval – события с указанным временным интервалом между ними Временные
  • 7. Горячие и холодные источники • Генерируют события только при подписке • Выдают каждому подписчику все сообщения с самого начала • Пример – ранее приведенные генераторы Холодные • Генерируют события независимо от наличия подписчиков • Выдают подписчикам события только в период подписки, разделяя каждое сообщение между всеми подписчиками • Пример – события от клавиатуры и мыши Горячие • Метод расширения Publish возвращает горячий источник, позволяя разделять одну подписку на холодный между несколькими наблюдателямиРазогрев
  • 8. Планировщики • Sheduler.Immediate – немедленное выполнение без планирования • Scheduler.CurrentThread – c контролем deadlock’овОднопоточные • Scheduler.NewThread – выполнение в новом потоке • Scheduler.TaskPool – выполнение в TPL.Task • Scheduler.ThreadPool – выполнение в пуле потоков Многопоточные • DispatcherScheduler – выполнение в потоке UI для WPF/Silverlight • ControlScheduler – то же для WinFormsUI • Автоматический – ничего указывать не надо, будет выбран наиболее подходящий • В LINQ – можно явно указать для последовательности с помощью метода ObserveOn Выбор
  • 9. Мосты • Методы ToObservale и ToEnumerable • Все стандартные ToXXX методы LINQ Последовательности и коллекции • Метод FromEventPattern • Можно указать методы для подписки и отписки • Для событий по шаблону EventHandler можно указать имя (найдется с помощью отражения) События • Метод FromAsyncPattern • Превращает вызов в поток событий с одним элементом - результатомАсинхронные вызовы • Метод расширения для задачи ToObservable • Метод расширения для источника ToTask (вернет последнее значение) • Задача от источника событий отличается только количеством результатов Задачи
  • 10. Drag & Drop • var mousedown = from evt in Observable.FromEvent<MouseButtonEventArgs>(this, "MouseDown") select evt.EventArgs.GetPosition(this); Нажатия • var mouseup = from evt in Observable.FromEvent<MouseButtonEventArgs>(this, "MouseUp" ) select evt.EventArgs.GetPosition(this); Отпускания • var mousemove = from evt in Observable.FromEvent<MouseEventArgs>(this, "MouseMove" ) select evt.EventArgs.GetPosition(this); Перемещения • var q = from start in mousedown from pos in mousemove.StartWith(start).TakeUntil(mouseup) select pos; Перетаскивание • q.ObserveOnDispatcher().Subscribe( value => textBlock.Text = value.ToString());Обновление UI
  • 11. Асинхронный вызов • Используется метод расширения using, гарантирующий вызов Dispose после завершения потока событий • Observable.Using(() => new WCFServiceClient() Автоочистка ресурсов • , client => Observable. FromAsyncPattern<RequestType, ResponseType>( client.BeginWCFMethod, client.EndWCFMethod)(request)) Конвертация вызова • .Subscribe( response => response.List.ForEach(WriteOutBusiness), ex => Console.WriteLine("Error = " + ex.Message), () => Console.WriteLine("Completed.")); Обработка результата
  • 12. Источники вдохновения 1. Шаблон разработки Observer 2. Композиционный стиль программирования с Reactive Extensions (презентация) 3. Библиотека реактивных расширений (видео) 4. Creating and Subscribing to Simple Observable Sequences 5. Jesse Liberty – Reactive 6. “Реактивные расширения” и асинхронные операции