Reduce busywaiting in ChannelStream components #197
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
When I want to read some bytes from the server, but I don't expect output to be available to be read immediately, I observe that even when the resulting system is "idle", the read call consumes an entire CPU core!
The cause is fairly straightforward: calling
Waker::wake_by_ref()
inpoll
and similar methods, in circumstances where the method didn't make any progress before activating the Waker, means a busywait. When there is an underlying asynchronous operation, proper behavior is obtained by passing the Waker to the underlying operation'spoll
method.In this case of the
ChannelRx
, I propose a very simple solution, made possible by https://docs.rs/tokio/latest/tokio/sync/mpsc/struct.UnboundedReceiver.html#method.poll_recv. Using this, I observe that I am able totail -f
an infrequently-written logfile with no CPU usage unless logfile contents are being transferred and processed.grep
told me thatChannelTx
has a similar problem; because its body is less simple than "await a future then do synchronous things with the result", my proposed solution is markedly less simple. It is also not 100% complete; it will still busywait for the window size to be increased from zero; the obvious answer to that would be a condvar, except that doing these 100% correctly in async Rust appears to be an unsolved problem and thus there isn't (yet) a condvar intokio::sync
.I've placed these in separate commits so that the
ChannelTx
change may be set aside if it is undesirable.