Reactive Extensions (Rx) - GOTO...

32
Reactive Extensions (Rx) Your prescription to cure event processing blues Bart J.F. De Smet Software Development Engineer [email protected]

Transcript of Reactive Extensions (Rx) - GOTO...

Page 1: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Reactive Extensions (Rx)Your prescription to cure event processing blues

Bart J.F. De SmetSoftware Development Engineer

[email protected]

Page 2: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Why should I care?

Social

media

RSS feeds

GPS

Server management

Page 3: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Event Processing Systems

Rx is a library for Rx is a library for Rx is a library for Rx is a library for composing composing composing composing asynchronous and eventasynchronous and eventasynchronous and eventasynchronous and event----basedbasedbasedbased

programs using programs using programs using programs using observable observable observable observable sequencessequencessequencessequences....

�� ����� � ��������� ◦ ����� � �������

Queries! LINQ!

Way simpler with Rx

• .NET 3.5 SP1, 4.0, and 4.5

• Silverlight 4, and 5

• Windows Phone 7 and 7.5

• JavaScript (RxJS)

Download at MSDN Data Developer Center or use NuGet

Page 4: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Observable Sequences

interface IObservable<out T>

{

IDisposable Subscribe(IObserver<T> observer);}

interface IObserver<in T>

{

void OnNext(T value);

void OnError(Exception ex);

void OnCompleted();

}

Mathematical Dual

of IEnumerable<T>

Page 5: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Environment

Mo

ve

Ne

xt

Got next?

Application

On

Ne

xt Have next!

IEnumerable<T>

IEnumerator<T>

IObservable<T>

IObserver<T>

Inte

ract

ive R

ea

ctive

Push-Based Data Retrieval

Page 6: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

DEMOThe IObservable<T> interface

Page 7: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Creating Observable Sequences

OnNext* [ OnError | OnCompleted ]

Observable.Empty<int>()

Observable.Return<int>(42)

Observable.Throw<int>(ex)

OnCompleted

OnNext(42)

OnError(ex)

Observable.Never<int>()

Page 8: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Generator Functions

var o = Observable.Generate(

0,

i => i < 10,

i => i + 1,

i => i * i

);

o.Subscribe(x => {

Console.WriteLine(x);

});

var e = new IEnumerable<int> {

for (int i = 0;

i < 10;

i++)

yield return i * i;

};

foreach (var x in e) {

Console.WriteLine(x);

}

SynchronousAsynchronous

Page 9: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

The Create operator

Observable<int> o = Observable.Create<int>(observer => {

// Assume we introduce concurrency (see later)…

observer.OnNext(42);

observer.OnCompleted();

return () => { /* unsubscribe action */ };

});

IDisposable subscription = o.Subscribe(

onNext: x => { Console.WriteLine("Next: " + x); },

onError: ex => { Console.WriteLine("Oops: " + ex); },

onCompleted: () => { Console.WriteLine("Done"); }

);

C# doesn’t have anonymous interface implementation, so we provide various extension methods that take lambdas.

C# 4.0 named parameter syntax

Page 10: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

The Create operator

F10

Observable<int> o = Observable.Create<int>(observer => {

// Assume we introduce concurrency (see later)…

observer.OnNext(42);

observer.OnCompleted();

return () => { /* unsubscribe action */ };

});

IDisposable subscription = o.Subscribe(

onNext: x => { Console.WriteLine("Next: " + x); },

onError: ex => { Console.WriteLine("Oops: " + ex); },

onCompleted: () => { Console.WriteLine("Done"); }

);

Thread.Sleep(30000);

Page 11: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

The Create operator

F10

Observable<int> o = Observable.Create<int>(observer => {

// Assume we introduce concurrency (see later)…

observer.OnNext(42);

observer.OnCompleted();

return () => { /* unsubscribe action */ };

});

IDisposable subscription = o.Subscribe(

onNext: x => { Console.WriteLine("Next: " + x); },

onError: ex => { Console.WriteLine("Oops: " + ex); },

onCompleted: () => { Console.WriteLine("Done"); }

);

Thread.Sleep(30000);

Page 12: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

The Create operator

F5

Observable<int> o = Observable.Create<int>(observer => {

// Assume we introduce concurrency (see later)…

observer.OnNext(42);

observer.OnCompleted();

return () => { /* unsubscribe action */ };

});

IDisposable subscription = o.Subscribe(

onNext: x => { Console.WriteLine("Next: " + x); },

onError: ex => { Console.WriteLine("Oops: " + ex); },

onCompleted: () => { Console.WriteLine("Done"); }

);

Thread.Sleep(30000);

Page 13: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

The Create operator

Breakpoint

got hit

Observable<int> o = Observable.Create<int>(observer => {

// Assume we introduce concurrency (see later)…

observer.OnNext(42);

observer.OnCompleted();

return () => { /* unsubscribe action */ };

});

IDisposable subscription = o.Subscribe(

onNext: x => { Console.WriteLine("Next: " + x); },

onError: ex => { Console.WriteLine("Oops: " + ex); },

onCompleted: () => { Console.WriteLine("Done"); }

);

Thread.Sleep(30000);

Page 14: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

DEMOCreating observable sequences

Page 15: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

The Trouble with .NET Events

Hidden data sourceHow to pass around?

Lack of composition

Resource maintenance?

form1.MouseMove.MouseMove.MouseMove.MouseMove += (sender, argsargsargsargs) => {if ((((args.Location.X == args.Location.Y))))

// I’d like to raise another event

};

form1.MouseMove ----==== /* what goes here? */

Page 16: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Observable Sequences are First-Class Objects

IObservableIObservableIObservableIObservable<<<<PointPointPointPoint>>>> mouseMoves = Observable.FromEventObservable.FromEventObservable.FromEventObservable.FromEvent(frm, "MouseMove");

var filtered = mouseMoves

.Where(.Where(.Where(.Where(pos => pos.X == pos.Y))));

var subscription = filtered.Subscribe(…);

subscription.Dispose.Dispose.Dispose.Dispose()()()();

Source of Point valuesObjects can be passed

Can define operators

Resource maintenance!

Page 17: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Other Conversions with IObservable<T>

• Asynchronous Programming Model (APM)

• Legacy support; prefer going through Task<T>

• Task<T>

• Way to represent single-value asynchrony

• IEnumerable<T>

• Pull-to-push conversion

Func<int, IObservable<int>> computeAsync = Observable.FromAsyncPattern.FromAsyncPattern.FromAsyncPattern.FromAsyncPattern(svc.BeginCompute,

svc.EndCompute);

Task<string> htmlTask = webClient.DownloadStringTaskAsync(uri)....ToObservableToObservableToObservableToObservable()()()();

IObservable<int> oneToNine = Enumerable.Range(0, 10)....ToObservableToObservableToObservableToObservable()()()();

But where does the

enumeration happen?

Page 18: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Asynchronous Data Processing Overview

Synchronous Asynchronous

#

Sin

gle

va

lue

(1

)M

ult

iple

va

lue

s (*

)

Func<T>

y = f(x);

Invocation expressions

Task<T>

y = await g(x);

Await expressions

IEnumerable<T> IObservable<T>

res = from x in xs from y in q(x) …;

foreach (var z in res)…

res.Subscribe(x =>…

Imp

era

tive

style

cod

eF

un

ction

alsty

le co

de

Sequencing through statements

Composition on query expressions

Page 19: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

DEMOConversions with IObservable<T>

Page 20: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Where is the Concurrency?

var ticks = Observable.Interval(TimeSpan.FromSeconds(1));ticks.Subscribe(_ => clock.Text = DateTime.Now.ToString());

Schedulers parameterize on concurrency

var ticks = Observable.Interval(TimeSpan.FromSeconds(1),Scheduler.ThreadPool);

ticks.ObserveOn(new ControlScheduler(clock)).Subscribe(_ => clock.Text = DateTime.Now.ToString());

Page 21: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

What are Schedulers?

• Single abstraction for concurrency

• new Thread(() => { … }).Start()

• ThreadPool.QueueUserWorkItem(_ => { … }, null);

• Task.Factory.StartNew(() => { … });

• Dispatcher.BeginInvoke(() => { … });

• Provide a notion of time

• Contains a clock

• Allows to schedule work with relative or absolute time

interface IScheduler{

DateTimeOffset Now { get; }

IDisposable Schedule<T>(T state,Func<IScheduler, T, IDisposable> action);

IDisposable Schedule<T>(T state, TimeSpan dueTime,Func<IScheduler, T, IDisposable> action);

IDisposable Schedule<T>(T state, DateTimeOffset dueTime,Func<IScheduler, T, IDisposable> action);

}

Allows for testing

by virtualizing time

Page 22: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

DEMOUsing the IScheduler construct

Page 23: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Querying Observable Sequences

• Using LINQ

• Support for Standard Query Operators

• Time-based operations

• Natural to the domain of event streams

• Time-out, delay, throttle

• Windows with time duration

IObservable<EventPattern<MouseEventArgs>> moves = Observable.FromEventPattern<MouseEventArgs>(frm, “MouseMove”);

IObservable<Point> diagonal = from move in moveslet point = move.EventArgs.Locationwhere point.X == point.Yselect point;

diagonal.Subscribe(point => {// Process the event

});

Page 24: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

ReactTextChanged

Dictionary web serviceDictionary web service

Asynchronousrequest

ReactionReactiveReactor

IObservable<string>

IObservable<DictionaryWord[]>

Data bindingon UI thread

Composition and Querying

Page 25: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

DEMOQuerying Observable Sequences using LINQ

Page 26: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Composition and Querying

// IObservable<string> from TextChanged events

var changed = Observable.FromEvent(txt, "TextChanged");

var input = (from text in changed

select ((TextBox)text.Sender).Text);

.DistinctUntilChanged()

.Throttle(TimeSpan.FromSeconds(1));

// Bridge with the dictionary web service

var svc = new DictServiceSoapClient();var lookup = Observable.FromAsyncPattern<string, DictionaryWord[]>

(svc.BeginLookup, svc.EndLookup);

// Compose both sources using SelectMany

var res = from term in input

from words in lookup(term)

select words;

input.SelectMany(term => lookup(term))

Page 27: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Beware of Concurrent Requests

inputinputinputinput

React Reactive

Service call 1

Service call 2

UI data binding

Reactive ReactionReactiveReactor

|R|Re|Rea|Reac|React|React|Reacti|Reactiv|Reactive|

ReactiveReactionReactiveReactor

Source: http://scrapetv.com

Page 28: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Beware of Concurrent Requests

inputinputinputinput

React Reactive

Service call 1

Service call 2

UI data binding

Reactive ReactionReactiveReactor

|R|Re|Rea|Reac|React|React|Reacti|Reactiv|Reactive|

Reactive Cancel call 1

Take

Un

til

Page 29: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Composition to the Rescue

// IObservable<string> from TextChanged events

var changed = Observable.FromEvent(txt, "TextChanged");

var input = (from text in changed

select ((TextBox)text.Sender).Text);

.DistinctUntilChanged()

.Throttle(TimeSpan.FromSeconds(1));

// Bridge with the dictionary web service

var svc = new DictServiceSoapClient();var lookup = Observable.FromAsyncPattern<string, DictionaryWord[]>

(svc.BeginLookup, svc.EndLookup);

// Compose both sources using SelectMany

var res = from term in input

from words in lookup(term).TakeUntil(input)

select words;

Page 30: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

Composition to the Rescue – Alternative Solution

// IObservable<string> from TextChanged events

var changed = Observable.FromEvent(txt, "TextChanged");

var input = (from text in changed

select ((TextBox)text.Sender).Text);

.DistinctUntilChanged()

.Throttle(TimeSpan.FromSeconds(1));

// Bridge with the dictionary web service

var svc = new DictServiceSoapClient();var lookup = Observable.FromAsyncPattern<string, DictionaryWord[]>

(svc.BeginLookup, svc.EndLookup);

// Using Switch to flatten nested sequences

var res = (from term in input

select lookup(term))

.Switch();

Page 31: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

DEMOTaming the Concurrency Monster

Page 32: Reactive Extensions (Rx) - GOTO Conferencegotocon.com/dl/...RxYourPrescriptionToCureEventProcessingBlues.pdf · Reactive Extensions (Rx) Your prescription to cure event processing

THANK YOU