-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RxJava 1, 2 & Reactor comparison benchmarks 14-03-2018 #7
Comments
This was referenced Mar 14, 2018
Open
Is the source code available? |
It's in this repo. |
Is it possible to compare Reactor 3 vs RxJava 3? |
Yes, but I can't do it myself for a few weeks. |
11 tasks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Environment
Memory usage
These tests check how much memory is allocated when working with 1,000,000 instances of varios flows and components (total megabytes, smaller is better, green is better):
Notes:
Flowable.empty()
is surprisingly largeAsync throughput
This benchmark measures how many items can be transferred over a flow when work stealing is possible (async) or the source and consumers are pinned to a specific thread (pipeline):
The tests use
Executor
s wrapped into schedulers, not the built-in schedulers. Reactor is clearly winning in both situations. The likely reason for this is that by default, the RxJava wrappers forExecutor
s always trampoline while Reactor's default wrapper does not, saving on double trampolining.Blocking
These benchmarks measure the overhead of blocking for the first or last element of a 1,000,000 source or how much overhead presents itself when blocking for an empty source (ops/s, larger is better):
For the 0-1 types, there is only 0 or 1 element to wait for blockingly:
Hot sources
These measure the throughput of various processor and subject types (ops/s, larger is better):
Subscribing
These measure the overhead of subscribing to various simple sources (ops/s, larger is better):
Single
type sources would emit a pre-created exception instead of an item.just
implementation.Streaming
There are various sub-benchmarks measuring the multi-value behavior of various flows:
array
These measure the throughput when the source data is in an array, which minimizes GC due to autoboxing (see range below):
just
implementation (count == 1 case).range
These measure the throughput when the source data is generated integers which get autoboxed, thus there is an additional GC overhead
just
implementation (count == 1 case).iterable
These measure the throughput when the source data is in an
Iterable
:Observable
perform worse despite the presumably lower overhead on longer sequences.concatMap onto just
These measure the throughput when a source sequence is mapped into plain
just
inner sources withinconcatMap
:Observable.concatMap
is not optimized for scalar sources, thus the code goes through the regular subscription routine, adding a lot of overhead.flatMap onto just
These measure the throughput when a source sequence is mapped into plain
just
inner sources withinflatMap
:The reason v1 is faster is because it uses
synchronized
as the trampolining mechanic which gets optimized away by the JIT. The v2 version uses lock-free atomics which can't be optimized away but should have much better concurrent properties.concatMap onto range
These measure the throughput when a source sequence is mapped onto a two element
range
withinconcatMap
:Observable
.flatMap onto range
These measure the throughput when a source sequence is mapped onto a two element
range
withinconcatMap
:Observable
.concatMap cross-mapping
In these throughput measures, the total number of items is always 1,000,000, which is made out of the outer item
count
times the individual inner items: 10 x 100,000; 100 x 10,000 etc. It tells about if theconcatMap
prefers long outer sources or long inner sources:flatMap cross-mapping
In these throughput measures, the total number of items is always 1,000,000, which is made out of the outer item
count
times the individual inner items: 10 x 100,000; 100 x 10,000 etc. It tells about ifflatMap
prefers long outer sources or long inner sources:flatten onto scalar
These measure the
flatMapIterable
(concatMapIterable
just an alias) performance which when mapped onto a singleton value. Unfortunately, there exist no standard way to detect anIterable
has a single value without trying to iterate through it.Observable
. It is worth investigating what causes the extra overhead inFlowable
.flatten onto a range
These measure the
flatMapIterable
(concatMapIterable
just an alias) performance which when mapped onto a two element source.flatten cross-mapping
In these throughput measures, the total number of items is always 1,000,000, which is made out of the outer item
count
times the individual inner items: 10 x 100,000; 100 x 10,000 etc. It tells about ifflatMapIterable
prefers long outer sources or long inner sources:Conclusion
Reactor core is sometimes better, sometimes worse than RxJava 2. At least they are mostly better than RxJava 1. There seems to be some opportunity for optimizing certain RxJava 2 operators further.
The text was updated successfully, but these errors were encountered: