Skip to content
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

Performance regression in Channel (EventQueue) for some usage patterns #762

Open
kjvalencik opened this issue Jun 29, 2021 · 0 comments
Open

Comments

@kjvalencik
Copy link
Member

Description

#739 introduced Clone for Channel (formerly EventQueue) that shares a backing Node-API threadsafe function.

Additionally, the cx.channel() (formerly cx.queue()) method has been changed to return a clone of a globally shared Channel.

In order to drop a referenced clone of a Channel, it must send an event back to be processed on the event loop to perform the unref. In most scenarios this is very fast because of an optimization in Node that will process multiple events within a single tick. nodejs/node#38506

This will result in better performance on recent Node versions with common usage patterns; however, there is one scenario where performance degradation is extreme (as much as 3x).

  • N-API Version 6+ (lower versions do not have a shared queue)
  • Node version less than 14.7.0 or 16.2.0
  • cx.channel() is used to create a Channel that is used once and dropped
  • Little to no concurrency

In this pathological example, the number of ticks required to process events are doubled.

Proposals

unref within event optimization

In many cases, the event sent to unref can be omitted completely when we know it is not possible for there to be other pending events that were sent on a referenced channel.

The advantage is that this will cover nearly all use cases. The issue is that it significantly increases the complexity of Channel. An additional counter will be required (either via an Arc on the inner state or a pending messages counter) to tell when it is safe to unref within that event. It is important not to unref when there are pending messages because it allows Node to exit immediately, even if it shouldn't.

Runtime version detection

Neon may check the currently running Node version and not give a shared Channel from cx.channel() if the Node version does not contain the multiple-events per tick optimization.

The advantage of this is that it's much simpler. The disadvantage is that it makes the operation of Neon less predictable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant