Share
Embed
RxJava, RxJava 2, Reactor: State of the art of Reactive Streams on the JVM
RxJava is used on Android or in backend side thanks to Hystrix. RxJava 2 is now available and will be able to use the path build by the previous version. Pivotal promote Reactor that will be available in Spring Boot 2.
What is the differences between each of these implementations of the Reactive Streams? Why chose RxJava 2 over Reactor or over RxJava?
This conference talk will focus on the history of each implementation then will compare APIs, performances and use cases of these Reactive Streams.
- DevDays Vilinus - may 2018
David
May 23, 2018
Transcript
183 slides
-
Got a question during this session? Post it on
sli.do ( #K100 ) -
RxJava, RxJava 2, Reactor State of the art of Reactive
Streams on the JVM -
Future ExecutorService ex = Executors.newCachedThreadPool(); Future<String> future = ex.submit(() ->
longProcessing()); String result = future.get(); Blocking call -
Future Future<?> future1 = /* ... */ Future<?> future2 =
/* ... */ Future<?> future3 = /* ... */ Future<?> future4 = /* ... */ Future<?> future5 = /* ... */ Optimal Orchestration ? -
Callback RemoteService service = buildRemoteService(); service.getUser(id -> { service.getData(id, data
-> { service.getSomething(data, whut -> { service.neverEndingCallBack(whut, () -> { }); }); }); }); Callback Hell -
RxJava is not compatible with Reactive Streams (You’ll have
to use an adapter: RxJavaReactiveStreams) https://github.com/ReactiveX/RxJavaReactiveStreams -
onNext * ( onError | onComplete ) onNext *
( onError | onCompleted ) RxJava Reactive Streams -
onNext * ( onError | onComplete ) onNext *
( onError | onCompleted ) RxJava Reactive Streams Different name -
A P I t o h a n d l
e e v e n t s synchronously or asynchronously through a flow of events -
remoteApi.people(1).flatMap(luke -> { Observable<String> vehicles = Observable.from(luke.getVehiclesIds()) .flatMap(remoteApi::vehicle) .map(vehicle
-> luke.getName() + " can drive " + vehicle.getName()); Observable<String> starships = Observable.from(luke.getStarshipsIds()) .flatMap(remoteApi::starship) .map(starship -> luke.getName() + " can fly with " + starship.getName()); return Observable.merge(vehicles, starships); }).subscribe(System.out::println); -
remoteApi.people(1).flatMap(luke -> { Observable<String> vehicles = Observable.from(luke.getVehiclesIds()) .flatMap(remoteApi::vehicle) .map(vehicle
-> luke.getName() + " can drive " + vehicle.getName()); Observable<String> starships = Observable.from(luke.getStarshipsIds()) .flatMap(remoteApi::starship) .map(starship -> luke.getName() + " can fly with " + starship.getName()); return Observable.merge(vehicles, starships); }).subscribe(System.out::println); Push of the result -
remoteApi.people(1).flatMap(luke -> { Observable<String> vehicles = Observable.from(luke.getVehiclesIds()) .flatMap(remoteApi::vehicle) .map(vehicle
-> luke.getName() + " can drive " + vehicle.getName()); Observable<String> starships = Observable.from(luke.getStarshipsIds()) .flatMap(remoteApi::starship) .map(starship -> luke.getName() + " can fly with " + starship.getName()); return Observable.merge(vehicles, starships); }).subscribe(System.out::println); Get Luke’s vehicles Get Luke’s starships -
remoteApi.people(1).flatMap(luke -> { Observable<String> vehicles = Observable.from(luke.getVehiclesIds()) .flatMap(remoteApi::vehicle) .map(vehicle
-> luke.getName() + " can drive " + vehicle.getName()); Observable<String> starships = Observable.from(luke.getStarshipsIds()) .flatMap(remoteApi::starship) .map(starship -> luke.getName() + " can fly with " + starship.getName()); return Observable.merge(vehicles, starships); }).subscribe(System.out::println); Merge of two flows -
remoteApi.people(1).flatMap(luke -> { Observable<String> vehicles = Observable.from(luke.getVehiclesIds()) .flatMap(remoteApi::vehicle) .map(vehicle
-> luke.getName() + " can drive " + vehicle.getName()); Observable<String> starships = Observable.from(luke.getStarshipsIds()) .flatMap(remoteApi::starship) .map(starship -> luke.getName() + " can fly with " + starship.getName()); return Observable.merge(vehicles, starships); }).subscribe(System.out::println); Really execute the code -
remoteApi.people(1).flatMap(luke -> { Observable<String> vehicles = Observable.from(luke.getVehiclesIds()) .flatMap(remoteApi::vehicle) .map(vehicle
-> luke.getName() + " can drive " + vehicle.getName()); Observable<String> starships = Observable.from(luke.getStarshipsIds()) .flatMap(remoteApi::starship) .map(starship -> luke.getName() + " can fly with " + starship.getName()); return Observable.merge(vehicles, starships); }).subscribe(System.out::println); Flow of events -
remoteApi.people(1).flatMap(luke -> { Observable<String> vehicles = Observable.from(luke.getVehiclesIds()) .flatMap(remoteApi::vehicle) .map(vehicle
-> luke.getName() + " can drive " + vehicle.getName()); Observable<String> starships = Observable.from(luke.getStarshipsIds()) .flatMap(remoteApi::starship) .map(starship -> luke.getName() + " can fly with " + starship.getName()); return Observable.merge(vehicles, starships); }).subscribe(System.out::println); Flow of events Flow of events -
Button btn = new Button(); btn.setText("Click Me"); JavaFx.fromClick(btn)
.observeOn(Schedulers.io()) .switchMap(evt -> remoteApi.getData()) .observeOn(javaFx()) .doOnNext(value -> btn.setText("Data: " + value)) .subscribe(); -
Button btn = new Button(); btn.setText("Click Me"); JavaFx.fromClick(btn) //
Observable<Event> .observeOn(Schedulers.io()) .switchMap(evt -> remoteApi.getData()) .observeOn(javaFx()) .doOnNext(value -> btn.setText("Data: " + value)) .subscribe(); Listen for clicks -
Button btn = new Button(); btn.setText("Click Me"); JavaFx.fromClick(btn) //
Observable<Event> .observeOn(Schedulers.io()) .switchMap(evt -> remoteApi.getData()) .observeOn(javaFx()) .doOnNext(value -> btn.setText("Data: " + value)) .subscribe(); Execution context switch -
Button btn = new Button(); btn.setText("Click Me"); JavaFx.fromClick(btn) //
Observable<Event> .observeOn(Schedulers.io()) .switchMap(evt -> remoteApi.getData()) // Observable<Data> .observeOn(javaFx()) .doOnNext(value -> btn.setText("Data: " + value)) .subscribe(); Asynchronous call to a web service -
Button btn = new Button(); btn.setText("Click Me"); JavaFx.fromClick(btn) //
Observable<Event> .observeOn(Schedulers.io()) .switchMap(evt -> remoteApi.getData()) // Observable<Data> .observeOn(javaFx()) .doOnNext(value -> btn.setText("Data: " + value)) .subscribe(); Execution context switch -
Button btn = new Button(); btn.setText("Click Me"); JavaFx.fromClick(btn) //
Observable<Event> .observeOn(Schedulers.io()) .switchMap(evt -> remoteApi.getData()) // Observable<Data> .observeOn(javaFx()) .doOnNext(value -> btn.setText("Data: " + value)) .subscribe(); Update on the UI -
Button btn = new Button(); btn.setText("Click Me"); JavaFx.fromClick(btn) //
Observable<Event> .observeOn(Schedulers.io()) .switchMap(evt -> remoteApi.getData()) // Observable<Data> .observeOn(javaFx()) .doOnNext(value -> btn.setText("Data: " + value)) .subscribe(); Flow of events -
Creation of Reactive Extensions Creation of RxJava Active Participation
Resumption of RxJava & RxJava 2 Creation of Reactor Work on Reactor -
RxJava Contrat Backpressure Observable [N] Yes Single [1] No Completable
[0] No Added afterward Web service call Background process -
Listen a websocket, for each received command, compose a response
by calling 3 different webservices, then execute 2 jobs sequentially ? -
Listen a websocket, for each received command, compose a response
by calling 3 different webservices, then execute 2 jobs sequentially ? -
Listen a websocket, for each received command, compose a response
by calling 3 different webservices, then execute 2 jobs sequentially ? -
Listen a websocket, for each received command, compose a response
by calling 3 different webservices, then execute 2 jobs sequentially ? -
websocket("/topics/cmd") .observeOn(Schedulers.io()) .switchMap(cmd -> Single.zip( api.getActions(), api.getScore(), api.getUserData(), this::composeResult).toObservable()) .observeOn(Schedulers.computation())
.concatMap(result -> updateDb(result).andThen(getLastResults())) .subscribe(last -> System.out.println("last results -> " + last)); -
websocket("/topics/cmd") .observeOn(Schedulers.io()) .switchMap(cmd -> Single.zip( api.getActions(), api.getScore(), api.getUserData(), this::composeResult).toObservable()) .observeOn(Schedulers.computation())
.concatMap(result -> updateDb(result).andThen(getLastResults())) .subscribe(last -> System.out.println("last results -> " + last)); Listen a websocket Observable -
websocket("/topics/cmd") .observeOn(Schedulers.io()) .switchMap(cmd -> Single.zip( api.getActions(), api.getScore(), api.getUserData(), this::composeResult).toObservable()) .observeOn(Schedulers.computation())
.concatMap(result -> updateDb(result).andThen(getLastResults())) .subscribe(last -> System.out.println("last results -> " + last)); Webservices composition Single -
websocket("/topics/cmd") .observeOn(Schedulers.io()) .switchMap(cmd -> Single.zip( api.getActions(), api.getScore(), api.getUserData(), this::composeResult).toObservable()) .observeOn(Schedulers.computation())
.concatMap(result -> updateDb(result).andThen(getLastResults())) .subscribe(last -> System.out.println("last results -> " + last)); Completable 2 jobs executions -
websocket("/topics/cmd") .observeOn(Schedulers.io()) .switchMap(cmd -> Single.zip( api.getActions(), api.getScore(), api.getUserData(), this::composeResult).toObservable()) .observeOn(Schedulers.computation())
.concatMap(result -> updateDb(result).andThen(getLastResults())) .subscribe(last -> System.out.println("last results -> " + last)); Listen a websocket Observable Webservices composition Single Completable 2 jobs executions -
RxJava 2 Contrat Backpressure Observable [N] No Single [1] No
Completable [0] No Maybe [0|1] No New! Close to Java 8 Optional -
acceptedIntent .filter(intent -> !intent.getBooleanExtra("UpdatePhoneMode", false)) .concatMap(intent -> approximatedEngine.detectCurrentPlace()) .doOnNext(score ->
Log.info(TAG, "Scan completed with result " + score)) .concatMap(this::detectSleepMode) .concatMap((score) -> isNewPlace(score.getScore().getPlace()).map(p -> score)) .doOnNext((p) -> Log.info(TAG, "Current place found is : " + p)) .subscribe() -
acceptedIntent .filter(intent -> !intent.getBooleanExtra("UpdatePhoneMode", false)) .onBackpressureDrop() .concatMap(intent -> approximatedEngine.detectCurrentPlace()) .doOnNext(score
-> Log.info(TAG, "Scan completed with result " + score)) .onBackpressureDrop() .concatMap(this::detectSleepMode) .onBackpressureDrop() .concatMap((score) -> isNewPlace(score.getScore().getPlace()).map(p -> score)) .doOnNext((p) -> Log.info(TAG, "Current place found is : " + p)) .subscribe() Added while I panicked -
RxJava 2 Contrat Backpressure Observable [N] No Single [1] No
Completable [0] No Maybe [0|1] No New! Close to Java 8 Optional -
RxJava 2 Contrat Backpressure Observable [N] No Single [1] No
Completable [0] No Maybe [0|1] No Flowable [N] Yes New! Observable with back pressure Close to Java 8 Optional -
Observable → less than 1000 events → User interface management
→ To be used instead of Java 8 Streams Flowable → more than 10 000 events → Control the data flow → Network stream with flow management -
Reactor Contrat Backpressure Flux [N] Yes Mono [0|1] Yes Identical
to Flowable Flux with only 1 element -
You can use a library which use RxJava 2 in
your Reactor project (and vice versa) -
all amb ambArray ambWith any as awaitOnSubscribe blockFirst blockFirstMillis blockLast
blockLastMillis blockingFirst blockingForEach blockingIterable blockingLast blockingLatest blockingMostRecent blockingNext blockingSingle blockingSubscribe buffer bufferMillis bufferSize bufferTimeout bufferTimeoutMillis bufferUntil bufferWhile cache cacheWithInitialCapacity cancelOn cast checkpoint collect collectInto collectList collectMap collectMultimap collectSortedList combineLatest combineLatestDelayError compose concat concatArray concatArrayDelayError concatArrayEager concatDelayError concatEager concatMap concatMapDelayError concatMapEager concatMapEagerDelayError concatMapIterable concatWith contains count create debounce defaultIfEmpty defer delay delayElements delayElementsMillis delayMillis delaySubscription delaySubscriptionMillis dematerialize distinct distinctUntilChanged doAfterNext doAfterTerminate doFinally doOnCancel doOnComplete doOnEach doOnError doOnLifecycle doOnNext doOnRequest doOnSubscribe doOnTerminate elapsed elementAt elementAtOrError empty equals error filter first firstElement firstEmitting firstEmittingWith firstOrError flatMap flatMapCompletable flatMapIterable flatMapMaybe flatMapSequential flatMapSingle forEach forEachWhile from fromArray fromCallable fromFuture fromIterable fromPublisher fromStream generate getClass getPrefetch groupBy groupJoin handle hasElement hasElements hashCode hide ignoreElements interval intervalMillis intervalRange isEmpty join just last lastElement lastOrError lift limitRate log map mapError materialize merge mergeArray mergeArrayDelayError mergeDelayError mergeSequential mergeWith never next notify notifyAll observeOn ofType onBackpressureBuffer onBackpressureDrop onBackpressureError onBackpressureLatest onErrorResumeNext onErrorResumeWith onErrorReturn onErrorReturnItem onExceptionResumeNext onTerminateDetach parallel publish publishNext publishOn range rangeLong rebatchRequests reduce reduceWith repeat repeatUntil repeatWhen replay replayMillis retry retryUntil retryWhen safeSubscribe sample sampleFirst sampleFirstMillis sampleMillis sampleTimeout scan scanWith sequenceEqual serialize share single singleElement singleOrEmpty singleOrError skip skipLast skipMillis skipUntil skipUntilOther skipWhile sort sorted startWith startWithArray strict subscribe subscribeOn subscribeWith switchIfEmpty switchMap switchMapDelayError switchOnError switchOnNext switchOnNextDelayError take takeLast takeMillis takeUntil takeUntilOther takeWhile test then thenEmpty thenMany throttleFirst throttleLast throttleWithTimeout timeInterval timeout timeoutMillis timer timestamp to toFuture toIterable toList toMap toMultimap toObservable toSortedList toStream toString transform unsafeCreate unsubscribeOn using wait window windowMillis windowTimeout windowTimeoutMillis windowUntil windowWhile withLatestFrom zip zipArray zipIterable zipWith zipWithIterable -
RxJava RxJava 2 Reactor flatMap flatMap flatMap Emit Noe, one
or more events amb amb firstEmitting Emit events from the first emitting stream … … … … debounce debounce N/A Ignore events during a time laps -
RxJava RxJava 2 Reactor flatMap flatMap flatMap Emit Noe, one
or more events amb amb firstEmitting Emit events from the first emitting stream … … … … debounce debounce N/A Ignore events during a time laps Renamed -
https://github.com/ReactiveX/RxJava/wiki/Implementing-custom-operators-(draft) writing operators is hard when one writes an operator,
the Observable protocol, unsubscription, backpressure and concurrency have to be taken into account and adhered to the letter -
Writing a new operator with RxJava 2 is more complex
than with RxJava -
RxJava RxJava 2 Reactor Flowable.just Flux.just Emitting existing value Flowable.defer
Flux.defer Lazy emitting Flowable.fromCallable Mono.fromCallable Lazy emitting, computed from a method call Flowable.create Flux.create Manual emitting Flowable.using Flux.using Resource management Flowable.fromPublisher Flux.from Using a Publisher (Reactive Streams) Flowable.generate Flux.generate Using a value generator -
RxJava RxJava 2 Reactor Flowable.just Flux.just Emitting existing value Flowable.defer
Flux.defer Lazy emitting Flowable.fromCallable Mono.fromCallable Lazy emitting, computed from a method call Flowable.create Flux.create Manual emitting Flowable.using Flux.using Resource management Flowable.fromPublisher Flux.from Using a Publisher (Reactive Streams) Flowable.generate Flux.generate Using a value generator -
RxJava RxJava 2 Reactor Flowable.just Flux.just Emitting existing value Flowable.defer
Flux.defer Lazy emitting Flowable.fromCallable Mono.fromCallable Lazy emitting, computed from a method call Flowable.create Flux.create Manual emitting Flowable.using Flux.using Resource management Flowable.fromPublisher Flux.from Using a Publisher (Reactive Streams) Flowable.generate Flux.generate Using a value generator -
RxJava RxJava 2 Reactor Flowable.just Flux.just Emitting existing value Flowable.defer
Flux.defer Lazy emitting Flowable.fromCallable Mono.fromCallable Lazy emitting, computed from a method call Flowable.create Flux.create Manual emitting Flowable.using Flux.using Resource management Flowable.fromPublisher Flux.from Using a Publisher (Reactive Streams) Flowable.generate Flux.generate Using a value generator -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis") private String redis() throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); AtomicReference<String> result = new AtomicReference<>(); this.connection.subscribe((message, pattern) -> { result.set(message.toString()); latch.countDown(); }, TOPIC_NAME); latch.await(); return result.get(); } } -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis") private String redis() throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); AtomicReference<String> result = new AtomicReference<>(); this.connection.subscribe((message, pattern) -> { result.set(message.toString()); latch.countDown(); }, TOPIC_NAME); latch.await(); return result.get(); } } -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis") private String redis() throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); AtomicReference<String> result = new AtomicReference<>(); this.connection.subscribe((message, pattern) -> { result.set(message.toString()); latch.countDown(); }, TOPIC_NAME); latch.await(); return result.get(); } } -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis") private String redis() throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); AtomicReference<String> result = new AtomicReference<>(); this.connection.subscribe((message, pattern) -> { result.set(message.toString()); latch.countDown(); }, TOPIC_NAME); latch.await(); return result.get(); } } Code for synchronisation Code for synchronisation -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis") private String redis() throws InterruptedException { String result = Flowable.create(sub -> { this.connection.subscribe((message, pattern) -> { sub.onNext(message.toString()); sub.onComplete(); }, TOPIC_NAME); }, BackpressureStrategy.BUFFER) .blockingFirst(); return result; } } -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis") private String redis() throws InterruptedException { String result = Flowable.create(sub -> { this.connection.subscribe((message, pattern) -> { sub.onNext(message.toString()); sub.onComplete(); }, TOPIC_NAME); }, BackpressureStrategy.BUFFER) .blockingFirst(); return result; } } Wrapping Synchronisation Reactive Contract -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis") private DeferredResult<String> redis() throws InterruptedException { DeferredResult<String> result = new DeferredResult<>(10_000l); Flowable.create(sub -> { this.connection.subscribe((message, pattern) -> { sub.onNext(message.toString()); sub.onComplete(); }, TOPIC_NAME); }, BackpressureStrategy.BUFFER) .subscribe(result::setResult); return result; } -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis") private DeferredResult<String> redis() throws InterruptedException { DeferredResult<String> result = new DeferredResult<>(10_000l); Flowable.create(sub -> { this.connection.subscribe((message, pattern) -> { sub.onNext(message.toString()); sub.onComplete(); }, TOPIC_NAME); }, BackpressureStrategy.BUFFER) .subscribe(result::setResult); return result; } Lazy result Use of DeferredResult -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE) private Flux<String> redis() throws InterruptedException { Flowable<String> rxjava = Flowable.create(sub -> { this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()), TOPIC_NAME); }, BackpressureStrategy.BUFFER); return Flux.defer(() -> rxjava); } } -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE) private Flux<String> redis() throws InterruptedException { Flowable<String> rxjava = Flowable.create(sub -> { this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()), TOPIC_NAME); }, BackpressureStrategy.BUFFER); return Flux.defer(() -> rxjava); } } RxJava 2 → Flux Flux → SSE Return a Flux -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE) private Publisher<String> redis() throws InterruptedException { return Flowable.create(sub -> { this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()), TOPIC_NAME); }, BackpressureStrategy.BUFFER); } -
@RestController public class HelloController { private static final byte[]
TOPIC_NAME = "topic".getBytes(); @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE) private Publisher<String> redis() throws InterruptedException { return Flowable.create(sub -> { this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()), TOPIC_NAME); }, BackpressureStrategy.BUFFER); } Publisher -
Task 1 Task 2 Task 3 Task 4 Scheduler
(Thread Pool) -
Task 1 Task 2 Task 3 Task 4 Scheduler
(Thread Pool) -
Task 1 Task 2 Task 3 Task 4 Scheduler
(Thread Pool) -
Task 1 Task 2 Task 3 Task 4 Scheduler
(Thread Pool) -
Task 1 Task 2 Task 3 Task 4 Scheduler
(Thread Pool) -
Task 1 Task 2 Task 3 Task 4 Scheduler
(Thread Pool) -
Task 1 Task 2 Task 3 Task 4 Scheduler
(Thread Pool) -
Task 1 Task 2 Task 3 Task 4 Scheduler
(Thread Pool) -
JavaFx.fromClick(btn) .observeOn(Schedulers.io()) .switchMap(evt -> remoteApi.getData()) .observeOn(Schedulers.computation()) .flatMap(data -> intensiveComputation(data))
.observeOn(javaFx()) .doOnNext(value -> btn.setText("Data: " + value)) .subscribe(); -
JavaFx.fromClick(btn) .observeOn(Schedulers.io()) .switchMap(evt -> remoteApi.getData()) .observeOn(Schedulers.computation()) .flatMap(data -> intensiveComputation(data))
.observeOn(javaFx()) .doOnNext(value -> btn.setText("Data: " + value)) .subscribe(); i/o computation UI Thread -
RxJava RxJava 2 Reactor Description io() io() elastic() Thread pool
which grow up if needed computation() computation() parallel() Limited thread pool single() single() single() Pool of 1 thread immediate() immediate() Execute the task immediately trampoline() trampoline() Queue the current task -
RxJava RxJava 2 Reactor Description io() io() elastic() Thread pool
which grow up if needed computation() computation() parallel() Limited thread pool single() single() single() Pool of 1 thread immediate() immediate() Execute the task immediately trampoline() trampoline() Queue the current task -
RxJava RxJava 2 Reactor Description io() io() elastic() Thread pool
which grow up if needed computation() computation() parallel() Limited thread pool single() single() single() Pool of 1 thread immediate() immediate() Execute the task immediately trampoline() trampoline() Queue the current task -
for (int x = 0; x < 10_000; x++) {
Observable.interval(10, TimeUnit.MILLISECONDS) .takeWhile(i -> take.get()) .flatMap(i -> Observable.range(1, 100)) .subscribe(); } -
RxJava RxJava 2 Reactor Retrofit Yes Yes No RxAndroid Yes
Yes No Realm Yes No No Hystrix Yes No No Couchbase Yes No No MongoDB Yes No No Spring Data 2.0 Yes No Yes Reactor IPC No No Yes WebFlux No Yes Yes Android Spring -
RxJava RxJava 2 Reactor Retrofit Yes Yes No RxAndroid Yes
Yes No Realm Yes No No Hystrix Yes No No Couchbase Yes No No MongoDB Yes No No Spring Data 2.0 Yes No Yes Reactor IPC No No Yes WebFlux No Yes Yes Android Spring -
We are aggressively migrating our internal code to RxJava
2 https://github.com/uber/AutoDispose -
RxJava RxJava 2 Reactor Retrofit Yes Yes No RxAndroid Yes
Yes No Realm Yes No No Hystrix Yes No No Couchbase Yes No No MongoDB Yes No No Spring Data 2.0 Yes No Yes Reactor IPC No No Yes WebFlux No Yes Yes Android Spring -
RxJava RxJava 2 Reactor Retrofit Yes Yes No RxAndroid Yes
Yes No Realm Yes No No Hystrix Yes No No Couchbase Yes No No MongoDB Yes No No Spring Data 2.0 Yes No Yes Reactor IPC No No Yes WebFlux No Yes Yes Android Spring -
Thanks for your attention We stay in touch? [email protected] @dwursteisen
http://blog.soat.fr Post your question on sli.do ( #K100 )