Top Banner
1 Tamir Dresher Senior Software Architect J Reactive Extensions 101
49

Rx 101 - Tamir Dresher - Copenhagen .NET User Group

Apr 12, 2017

Download

Software

Tamir Dresher
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

1

Tamir DresherSenior Software ArchitectJ

Reactive Extensions 101

Page 2: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

222

• Software architect, consultant and instructor• Software Engineering Lecturer @ Ruppin Academic Center• Reactive Extensions in .NET (Manning)

@[email protected]://www.TamirDresher.com.

About Me

Page 3: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Reactive Extensions

Your headache relief pill to Asynchronous Event based applications

AsyncPush

TriggersEvents

Page 4: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Reacting to changes

4

Page 5: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

5

Socialmedia

High Rate Data

IoTGPS

External Services

UI eve

nts

Your System

So Many Sources…So Many Sources…

Page 6: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Agenda

Rx building blocks – Observable and ObserversCreating ObservablesRx queries with Rx operatorsManaging Concurrency with Rx Schedulers

6

Page 7: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Source/Producer

Target/Consumer

Producer-ConsumerProducer-Consumer

Page 8: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Source/Producer

Target/Consumer

Source/Producer

Source/Producer

Target/Consumer

Target/Consumer

Producer-ConsumerProducers-Consumers

Page 9: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

IEnumerable<Message> LoadMessages(string hashtag){

var statuses = facebook.Search(hashtag);var tweets = twitter.Search(hashtag);var updates = linkedin.Search(hashtag);return statuses.Concat(tweets).Concat(updates);

}

Twitter App

Linkedin

Facebook

Pull ModelPull Model

Page 10: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

???? LoadMessages(string hashtag){

facebook.Search(hashtag);twitter.Search(hashtag);linkedin.Search(hashtag);

}

DoSomething( )msg

Push ModelPush Model

Page 11: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Push model with Events

11

var mgr = new SocialNetworksManager();mgr.MessageAvailable += (sender, msg) => {//do something};mgr.LoadMessages("Rx");

class SocialNetworksManager{ //members

public event EventHandler<Message> MessageAvailable; public void LoadMessages(string hashtag) { var statuses = _facebook.Search(hashtag); NotifyMessages(statuses); : }}

hard to unsubscribe non-composable

can’t send as argument

no isolation

Page 12: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

???? LoadMessages(string hashtag){

facebook.Search(hashtag);twitter.Search(hashtag);linkedin.Search(hashtag);

}

DoSomething( )msg

Push ModelPush Model

Page 13: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

observable observer

Subscribe(observer)

subscription

OnNext(X1)

OnNext(Xn)⁞

X1observable X2 Xn

IDisposable

Observables and ObserversObservables and Observers

Page 14: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

OnCompleted()

OnError(Exception)

observable

observable observer

X1 X2 Xn

Observables and ObserversObservables and Observers

Page 15: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

namespace System{ 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(); }}

InterfacesInterfaces

Page 16: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Rx packages

16

Page 17: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Push ModelPush Model with Rx Observables

class ReactiveSocialNetworksManager{ //members public IObservable<Message> ObserveMessages(string hashtag) {

: }}

var mgr = new ReactiveSocialNetworksManager();

mgr.ObserveLoadedMessages("Rx")    .Subscribe(        msg => Console.WriteLine($"Observed:{msg} \t"),        ex => { /*OnError*/ },        () => { /*OnCompleted*/ });

Page 18: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Creating Observables

Page 19: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

IObservable<Message> ObserveMessages(string hashtag){

}

return Observable.Create( async (o) => {

});

var messages = await GetMessagesAsync(hashtag);foreach(var m in messages){ o.OnNext(m);}o.OnCompleted();

Pull To PushPull To Push

Subscribe function

FacebookClient:    

Page 20: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

IObservable<Message> ObserveMessages(string hashtag){

}

var messages = await GetMessagesAsync(hashtag);return messages.ToObservable();

Built-in ConvertersBuilt-in Converters

Note: All observers will get the same emitted messages

Page 21: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

IObservable<Message> ObserveMessages(string hashtag){

}

return Observable.Defer( async () => {

});

var messages = await GetMessagesAsync(hashtag);return messages.ToObservable();

Built-in ConvertersDefering the observable creation

Note: Every observer will get the “fresh” emitted messages

Page 22: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Observable.Merge(

facebook.ObserveMessages(hashtag),

twitter.ObserveMessages(hashtag),

linkedin.ObserveMessages(hashtag));

Built-in OperatorsBuilt-in Combinators (combining operators)

Page 23: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Observable.Range(1, 10)    .Subscribe(x => Console.WriteLine(x));

Observable.Interval(TimeSpan.FromSeconds(1))    .Subscribe(x => Console.WriteLine(x));

Observable.FromEventPattern(SearchBox, "TextChanged")

1 2 10

1 2 10

⁞1 sec 1 sec

Observables Factories

Observables Factories

Page 24: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Observable Queries (Rx Operators)

Page 25: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Filtering Projection Partitioning Joins Grouping Set

Element Generation Quantifiers Aggregation Error HandlingTime and Concurrency

Where

OfType

Select

SelectMany

Materialize

Skip

Take

TakeUntil

CombineLatest

Concat

join

GroupBy

GroupByUntil

Buffer

Distinct

DistinctUntilChanged

Timeout

TimeInterval

ElementAt

First

Single

Range

Repeat

Defer

All

Any

Contains

Sum

Average

Scan

Catch

OnErrorResumeNext

Using

Rx operators

Page 26: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Operator2 Creates an IObservable<T3>

IObservable<T2> Operator<T1>(IObservable<T1> source, parameters);

Operator 1 Subscribe( )

observer

observable… Operator

N

Operator1 Creates an IObservable<T2>

IObservable<T>Original source

observerSubscribe

ComposabilityComposability

Page 27: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

g(x)

f(x)

Observable Query PipelineObservable Query Pipeline

Page 28: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Reactive SearchReactive Search

Page 29: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

1. At least 3 characters2. Don’t overflow server (0.5 sec delay)3. Don’t send the same string again4. Discard results if another search was requested

Reactive Search - RulesReactive Search - Rules

Page 30: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Demo

Click icon to add picture

Page 31: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

31

R RE REACREA REA REAC

Page 32: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

32

R RE REACREA

REACREA

REA REAC

REA REAC

Where(s => s.Length > 2 )

Page 33: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

33

R RE REACREA

REACREA

REA REAC

REA REAC

Where(s => s.Length > 2 )

Throttle(TimeSpan.FromSeconds(0.5))

REACREA REAC

Page 34: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

34

R RE REACREA

REACREA

REA REAC

REA REAC

Where(s => s.Length > 2 )

Throttle(TimeSpan.FromSeconds(0.5))

REACREA REAC

DistinctUntilChanged()

REACREA

Page 35: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

36

REACREA

Select(text => SearchAsync(text))

“REA”

“REAC”

Switch()

“REA” results are ignored since we switched to the “REAC” results

Page 36: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Var textChanged = Observable.FromEventPattern(txt,

“TextChanged”).Select(_=>txt.Text);

textChanged.Where(text=>text.Length>3).Throttle(TimeSpan.FromSeconds(0.5)).DistinctUntilChanged().SelectMany(text => SearchAsync(text)).Switch().Subscribe(/*handle the results*/);

Page 37: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

var $input = $('#input'), $results = $('#results');

Rx.Observable.fromEvent($input, 'keyup') .map(e => e.target.value) .filter(text => text.length > 3) .throttle(500 /* ms */) .distinctUntilChanged() .flatMapLatest(searchWikipedia) .subscribe(data => { var res = data[1]; $results.empty(); $.each(res, (_, value) => $('<li>' + value + '</li>').appendTo($results)); }, error => { /* handle any errors */ $results.empty(); $('<li>Error: ' + error + '</li>').appendTo($results);});

Page 38: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Abstracting Time and Concurrency

Page 39: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

What will be the output?

The Repeat operator resubscribes the observer when the observable completes

Most developers falsely believe that the program will immediately dispose the subscription and nothing will be written to the consoleRx is not concurrent unless it explicitly told to

The example above writes the sequence 1-5 indefinitely to the console

40

var subscription = Observable.Range(1, 5) .Repeat() .Subscribe(x => Console.WriteLine(x));

subscription.Dispose();

Page 40: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Thread Pool

Task Scheduler

other

SchedulersSchedulers

Page 41: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

public interface IScheduler{ DateTimeOffset Now { get; }

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

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

IDisposable Schedule<TState>(DateTimeOffset dueTime,

TState state,Func<IScheduler, TState, IDisposable> action);

}

Page 42: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

//// Runs a timer on the default scheduler//IObservable<T> Throttle<T>(TimeSpan dueTime);

//// Every operator that introduces concurrency// has an overload with an IScheduler//IObservable<T> Throttle<T>(TimeSpan dueTime, IScheduler scheduler);

Parameterizing ConcurrencyParameterizing Concurrency

Page 43: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

textChanged.Throttle(TimeSpan.FromSeconds(0.5),

DefaultScheduler.Instance).DistinctUntilChanged().SelectMany(text => SearchAsync(text)).Switch().Subscribe(/*handle the results*/);

Page 44: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

//// runs the observer callbacks on the specified // scheduler.//IObservable<T> ObserveOn<T>(IScheduler);

//// runs the observer subscription and unsubsciption on// the specified scheduler.//IObservable<T> SubscribeOn<T>(IScheduler)

Changing Execution ContextChanging Execution Context

Page 45: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

textChanged.Throttle(TimeSpan.FromSeconds(0.5)).DistinctUntilChanged().Select(text => SearchAsync(text)).Switch()

.ObserveOn(DispatcherScheduler.Current).Subscribe(/*handle the results*/);

Changing Execution ContextChanging Execution Context

Page 46: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

textChanged.Throttle(TimeSpan.FromSeconds(0.5)).DistinctUntilChanged().Select(text => SearchAsync(text)).Switch().ObserveOnDispatcher().Subscribe(/*handle the results*/);

Changing Execution ContextChanging Execution Context

Page 47: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

Your headache relief pill to Asynchronous and Event based applications

AsyncPush

TriggersEvents

Reactive ExtensionsReactive Extensions

Page 48: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

www.manning.com/dresher www.reactivex.io github.com/Reactive-Extensions

Discount code: dreshermu  

Thank You

Page 49: Rx 101  - Tamir Dresher - Copenhagen .NET User Group

What will the following Console app print out?

51

http://landing.oz-code.com/CPH