-
Notifications
You must be signed in to change notification settings - Fork 3k
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
perf(bufferCount): optimize bufferCount operator #2359
Conversation
Yay! Great work, thanks a lot @martinsik |
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.
Minor nits, otherwise looking good!
src/operator/bufferCount.ts
Outdated
while (buffers.length > 0) { | ||
let buffer = buffers.shift(); | ||
if (buffer.length > 0) { | ||
destination.next(buffer); | ||
this.destination.next(buffer); |
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.
destination
lookup used to be cached above, so it doesn't need to happen every time. Seemed like a simple win for micro perf?
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.
@jayphelps I removed the const
because this.destination
is used just once in this method. Maybe I don't understand what you mean.
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.
@martinsik this is inside a loop, is it not possible for the branch inside to call destination.next() multiple times? Seems like it would be.
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.
@jayphelps is correct here, you'll want to access the property outside of the loop and put in in a const
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.
@Blesh @jayphelps Ahaaaa, I see it now :).
src/operator/bufferCount.ts
Outdated
|
||
if (count % startOn === 0) { | ||
if (this.count++ % startBufferEvery === 0) { |
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.
I would prefer if we don't increment inside a conditional. I understand it just fine, but I've seen it be unnecessarily confusing for many. Can we increment before we enter the conditional?
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.
@jayphelps done!
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.
move property accessor outside of the loop.
src/operator/bufferCount.ts
Outdated
while (buffers.length > 0) { | ||
let buffer = buffers.shift(); | ||
if (buffer.length > 0) { | ||
destination.next(buffer); | ||
this.destination.next(buffer); |
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.
@jayphelps is correct here, you'll want to access the property outside of the loop and put in in a const
Same as my concerns... seem to have been met.
Thank you @martinsik! |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
The
bufferCount()
operator can be used asbufferCount(5, 3)
orbufferCount(5)
(=bufferCount(5, 5)
.My assumption is that the second use-case
bufferCount(5)
is very common (maybe even more common that the first one) and can be handled in an simpler way. This means instead of keeping an array of buffersT[][]
we can have just a single bufferT[]
. This simplifies the subscriber class significantly and runs faster.For this reason I split the original subscriber into two classes
BufferSkipCountSubscriber
andBufferCountSubscriber
each handling one use-case.Performance of
bufferCount(5)
:Before:
After:
This improves performance on the
buffercount - immediate
script roughly from23.24x
to39.83x
andbuffercount
from15.88x
to21.88x
.Performance of
bufferCount(5, 3)
remains the same. I could just remove one additional condition that wasn't necessary any more when we have two separate classes now.I also tried to make an implementations using only fixed size arrays for both use-cases but these always turned out to be less efficient than the current implementation. It required calculating indices on every
next()
, at least one additionalif
condition and callingArray.split()
to clone the buffer when callingdestination.next(...)
. UsingArray.push()
withoutArray.split()
was always faster.