-
Notifications
You must be signed in to change notification settings - Fork 7.6k
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
Optimization - use OperatorTakeLastOne for takeLast(1) #2914
Conversation
T t = last; | ||
// release for gc | ||
last = null; | ||
child.onNext(t); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never call onNext while holding a lock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you are calling child.onNext
from onCompleted
, you need to bounce back any thrown exceptions because throwing onCompleted
can't be routed back to onError
and child will not receive the exception.
@@ -7771,7 +7771,10 @@ public final Subscription subscribe(Subscriber<? super T> subscriber) { | |||
* @see <a href="http://reactivex.io/documentation/operators/takelast.html">ReactiveX operators documentation: TakeLast</a> | |||
*/ | |||
public final Observable<T> takeLast(final int count) { | |||
return lift(new OperatorTakeLast<T>(count)); | |||
if (count == 1 ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is takeLast(0)
meaningful? If so, it can be routed to ignoreElements()
. BTW, ignoreElements()
can be optimized by making it singleton and be very simple (i.e., its onNext does nothing) instead of filtering with always false.
7692618
to
0954ee8
Compare
Thanks @akarnokd for the review, I appreciate the lessons! I've incorporated the changes except for the I wrote this up before you submitted the Up to you of course if you want to merge this or wait for #2901 to be merged then get another PR that uses a modified Updated benchmarks (that's a nifty trick using Params):
|
public void onCompleted() { | ||
// CAS loop to atomically change state given that requestMore() | ||
// may be acting concurrently | ||
while (true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If last == ABSENT
then there is no need to interact with the backpressure logic since a plain onCompleted can be sent before any request. In this case, I'd also not check isUnsubscribed().
0954ee8
to
9d96b79
Compare
Thanks @akarnokd. I've added your suggestions:
|
Thanks! |
Optimization - use OperatorTakeLastOne for takeLast(1)
👍 |
This is an optimization for
takeLast
when called with parameter 1. UsingOperatorTakeLast
carries unnecessary overhead for thetakeLast(1)
case and a decent throughput improvement (x2) for streams of 100 elements or more is seen in the benchmarks below.takeLast(1)
is used by the following operators which will also demonstrate a throughput improvement:last
,lastOrDefault
reduce
collect
count
,countLong
Benchmarks comparing using the new
OperatorTakeLastOne
andOperatorTakeLast
: