430 likes | 650 Views
Reactive Libs Review Observable/Design Pattern Observables Streams JavaRx Demo ScalaRxShell Demo. Observables. RxLibs. Microsoft open source https://rx.codeplex.com/ Open source implementations of ReactiveX: https://github.com/ReactiveX/RxJava https://github.com/ReactiveX/RxScala
E N D
Reactive Libs Review Observable/Design Pattern Observables Streams JavaRx Demo ScalaRxShell Demo Observables
RxLibs • Microsoft open source • https://rx.codeplex.com/ • Open source implementations of ReactiveX: • https://github.com/ReactiveX/RxJava • https://github.com/ReactiveX/RxScala • Netflix open source: • http://techblog.netflix.com/2013/02/rxjava-netflix-api.html • Additions on ReactiveX, competition to akka
Observable/Observer not reactive • Java Design pattern. Not useful for async or distributed systems. Pre 2000. package com.example; import java.util.Observable; import java.util.Observer; //models customer going to coffeeshop. can change name. leave observer public class MyObserver implements Observer{ private String name=null; private boolean atCoffeeShop=false; MyObserver(String n){ this.name=n; } @Override public void update(Observable o, Object arg) { // TODO Auto-generated method stub System.out.println("calling update callback for:"+name); } }
Observable • package com.example; • import java.util.Observable; • public class CoffeeShop extends Observable{ • public void enterCoffeeShop(MyObserver obs){ • addObserver(obs); • } • public void notifyCustomers(){ • setChanged(); • notifyObservers(); • } • }
Main.java • package com.example; • public class Main{ • public static void main(String []args){ • CoffeeShop cs = new CoffeeShop(); • cs.addObserver(new MyObserver("cust1")); • cs.addObserver(new MyObserver("cust2")); • cs.addObserver(new MyObserver("cust3")); • cs.notifyCustomers(); • } • } • Output: • calling update callback for:cust3 • calling update callback for:cust2 • calling update callback for:cust1
Run instr: • Download zip: https://github.com/dougc333/TestCode • Unarchive, cd TestCode-master/TestObservable, mvn compile • $ mvn exec:java -Dexec.mainClass=com.example.Main • [WARNING] Warning: killAfter is now deprecated. Do you need it ? Please comment on MEXEC-6. • calling update callback for:cust3 • calling update callback for:cust2 • calling update callback for:cust1
RxJava • NOT ASYNC • the Coffeeshop/Observable notifies all the observers via callback function. JavaRx, JavaRxScala add to this design pattern for event streams and to make async programming possible. • EventStreams=Subscriptions • Async: Try/onNext,onComplete • No Locks, Threads, etc...abstracted away • Note: code style cleaner than Observer/Observable. Everything in subscription class. No separate driver program needed • http://docs.couchbase.com/prebuilt/java-sdk-2.0-beta/topics/observables.html
RxJava • Create an observerable stream using .just(1,2,3) • Add a subscriber(lazy eval), similar to observer but add the duality of iterables. Iterable/Observer stream programming. Iterables block/bad perf. JavaRx adds threads + async • onNext <-> next() • onComplete ↔ hasNext() • onError ↔ throws exception
RxJava Create stream, print • package com.example; • import rx.Observable; • public class TestObservable{ • public static void main(String []args){ • System.out.println("asdf"); • Observable.just(5,6,7,8).subscribe(new MySubscriber<Integer>()); • //endless stream • //Observable.just(5,6,7,8).repeat().subscribe(new MySubscriber<Integer>()); • } • }
Subscriber • import rx.Subscriber; • class MySubscriber<Integer> extends Subscriber<Integer>{ • @Override • public void onCompleted() { • // TODO Auto-generated method stub • System.out.println("onCompleted"); • } • @Override • public void onError(Throwable throwable) { • // TODO Auto-generated method stub • System.err.println(Error: " + throwable.getMessage()); • } • @Override • public void onNext(Object arg0) { • // TODO Auto-generated method stub • System.out.println("onNext: " + arg0); • } • }
Run instr: • cd TestObservable/TestJavaRx • mvn clean;mvn compile • $ mvn exec:java -Dexec.mainClass=com.example.TestObservable [WARNING] Warning: killAfter is now deprecated. Do you need it ? Please comment on MEXEC-6. onNext: 5 onNext: 6 onNext: 7 onNext: 8 onComplete
RxJava Create • static <T> Observable<T> create(Observable.OnSubscribe<T> f) • Returns an Observable that will execute the specified function when a Subscriber subscribes to it.
Create a separate class • package com.example; • import rx.*; • //implement logic when to call onNext(), onError(), onComplete() by using create() • //demo only • public class CreateObservable<Integer> implements Observable.OnSubscribe<Integer>{ • @Override • public void call(Subscriber<? super Integer> arg0) { • // TODO Auto-generated method stub • Subscriber subscriber = (Subscriber) arg0; • try{ • if(!subscriber.isUnsubscribed()){ • for(int i=0;i<5; i++){ • subscriber.onNext(i); • } • subscriber.onCompleted(); • } • }catch(Exception e){ • subscriber.onError(e); • } • } • }
Add subscribe. No drivers!!! • package com.example; • import rx.*; • import rx.functions.Action1; • public class ObservableCreate { • public static void main(String args[]){ • Observable.create(new CreateObservable<Integer>()).subscribe(new Action1<Integer>() { • @Override • public void call(Integer integer) { • System.out.println("onNext: " + integer); • } • }); • } • }
Run Instr: • Run from eclipse
Run from eclipse • Run function Action1 everytime subscriber subscribes. Lazy eval, have to call subscribe to start data processing
RxJava API Example • Some things are easier in RxJava, create a counter once per second. No locks, no threads. Errors and cancellation(unsubscribe) built into the API. Less custom code and less testing.
Timer.java • package com.example; • import rx.*; • import rx.functions.Action1; • import java.util.concurrent.*; • public class Timer { • static CountDownLatch latch = new CountDownLatch(5); • public static void main(String args[]) throws InterruptedException{ • Observable.interval(1,TimeUnit.SECONDS).subscribe(new Action1<Long>(){ • public void call(Long counter){ • latch.countDown(); • System.out.println("Timer Secs:"+counter); • } • }); • latch.await(); • } • }
Run Inst; • Run in eclipse
RxJava Map Java7 • Uses functions to replace the x=>f(x) notation • Modify the timer example to use a map to print out the thread it is operating on • Use the testing code. • The countdown latch for interval sequences when another thread creates the sequence. • Interval is threaded, see scheduler operator table:https://github.com/ReactiveX/RxJava/wiki/Scheduler#using-schedulers
Timer threads • The observable does the work in one thread and the results via the subscriber are displayed in another thread. class RxThread[T](o:Observable[T]) { def execAsync[T] = { o.subscribeOn(Schedulers.newThread) .observeOn(AndroidSchedulers.mainThread()) .materialize } } /** * Convert implicitly a Java Observable in a Scala Observable. */ object RxThread { implicit def Observable2Notification[T](o: Observable[T]) = new RxThread(o) }
Add func • publicstaticvoid debugTimer() throws InterruptedException{ • Observable.interval(1,TimeUnit.SECONDS).map(new Func1<Long,Long>(){ • @Override • public Long call(Long i){ • System.out.println(Thread.currentThread().getName()); • return i; • } • }).subscribe(new Action1<Long>(){ • publicvoid call(Long counter){ • latch.countDown(); • System.out.println("Timer Secs:"+counter); • } • }); • latch.await(); • }
How about a sequence? • publicstaticvoid debugSeq() { • Observable.just(1,2,3,4,5).map(new Func1<Integer,Integer>(){ • @Override • public Integer call(Integer i){ • System.out.println(Thread.currentThread().getName()); • return i; • } • }).subscribe(new Action1<Integer>(){ • @Override • publicvoid call(Integer i){ • System.out.println("onNext: " + i); • } • }); • }
Run inst; • Comment out either debugTimer() or debugSeq() , run Timer.java in Eclipse or maven
RxJava Twitter Ex. Building APIs • http://java.dzone.com/articles/turning-twitter4j-rxjavas • Turning Twitter4J into Observable. Creates API for stream processing/multiuser nonblocking. • Goal: API for user, rolling count of tweets
Making RxJava Async and Parallel • Trick from lecture: if the return type is <T> this is blocking. If Observable<T> or Future<T> then this is async. • Look at BlockingObservable return types. Marble diagram=>parallel
JavaRx parallel • JavaRx controls thread pools using schedulers as describe in lecture when EM compared ExecutionContext from Promises/Futures to Observables. • Just using flatMap doesn't guarantee multiple threads. A flatMap returns Observable<T> which is the first criteria for parallelism
Schedulers add parallelism • Debug:Thread.getCurrentThread().getName(), getCount() • Debug threads in JavaRx/Java adding to map() using Func1 • Debug in Rx/Scala adding .debug() to package.scala • http://www.grahamlea.com/2014/07/rxjava-threading-examples/
Multiple ways to add threads • Docs not clear, look at the JavaRx test code • Test code does this: Creating your own threads • In the observable call? • OnNext()? • Blog does this: Using the thread pool from the scheduler • Add spark executors or create your own executor framework using zookeeper(TBD)
Rx/Scala • Scala wrapper around a RxJava • https://github.com/ReactiveX/RxScala • Scala REPL for Observables • Not avail from websearch • Change $TOOL_PATH under $SCALA_HOME/bin or copy the jars from suggestions/lib_managed/com.netflix.rxjava and rxjava-scala into $SCALA_HOME/lib dir.
JavaRx • The APIs are different between JavaRx/JavaRxScala/JavaRxNET • From lecture: • Create a stream, notify subscribers on change to represent processing, • schedulers manage thread pools vs. ExecutionContext in Futures, • apply ops to streams which return Observables
Scala REPL bug • scala> import rx.lang.scala._ • scala> val ob = Observable(1,2,3,4) • java.lang.NoSuchMethodError: scala.collection.JavaConverters$.asJavaIterableConverter(Lscala/collection/Iterable;)Lscala/collection/convert/Decorators$AsJava; • at rx.lang.scala.Observable$.apply(Observable.scala:1924)
Upgrade to latest scala version; 2.11.2; 2 I/Fs, RxScala • scala> import rx.lang.scala._ • import rx.lang.scala._ • scala> val ob = Observable(1,2,3,4) • ob: rx.lang.scala.Observable[Int] = rx.lang.scala.Observable$$anon$9@750cdd5e • scala>
Importing the wrong lib, RxJava • scala> import rx._ • import rx._ • scala> val foo = Observable.just(1,2,3,4) • foo: rx.Observable[(Int, Int, Int, Int)] = rx.Observable@18a8422d • scala>
Upgrade to latest scala version; 2.11.2 • scala> import rx.lang.scala._ • import rx.lang.scala._ • scala> val ob = Observable(1,2,3,4) • ob: rx.lang.scala.Observable[Int] = rx.lang.scala.Observable$$anon$9@750cdd5e • scala>
Import the netflix jars(no scheduler) • Download from maven central, use the .20.4 versions not the 0.15.0 versions in the hw • rxjava-async-util-0.20.4.jar • rxjava-computation-expressions-0.20.4.jar • rxjava-core-0.15.0.jar • rxjava-core-0.20.4.jar • rxjava-scala-0.15.0.jar • rxjava-scala-0.20.4.jar
Subscribe to the Observable, much easier than Java7 • scala> foo.subscribe(x=>println(x)) • 1 • 2 • 3 • 4 • res0: rx.lang.scala.Subscription = rx.lang.scala.subscriptions.Subscription$$anon$1@4f91659c
Observables • Repeat Rx in Scala • Observables require subscribers to send notifications to when data is ready in the Observable. An observable is the dual of an iterator but can return 0 or many events or an Error. Key is the 0 event. Doesn't have to be async • An observable interface contains: • onNext • onError • onCompleted
RxScala • Homework • apply() (for maps, flatMap) • Add what on top of adding subscribers to observables?
Subjects • For async programming, a subject is like a promise. A promise contains a future just as a future has to wait for a promise to write the data • A subject contains an Observable<T> or Observer<T>?