Skip to content

feat(channel): add is_empty to mpsc and mpmc receivers - #392

Merged
orthur2 merged 1 commit into
apache:mainfrom
FalkWoldmann:channel-len
Nov 1, 2026
Merged

orthur2 merged 1 commit into
apache:mainfrom
FalkWoldmann:channel-len

Conversation

@FalkWoldmann

@FalkWoldmann FalkWoldmann commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #377. Adds is_empty to the mpsc and mpmc receivers, so an event loop can check for queued values without receiving. Held permits and sends still waiting for capacity don't count. I kept it on the receivers only, like tokio: the unbounded mpsc receiver holds a local batch the senders can't see, so a sender-side check would be off there

@tisonkun
tisonkun requested review from ariesdevil, orthur2 and tisonkun and a balanced review from Copilot November 1, 2026 10:47

@tisonkun tisonkun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's generally OK to add an is_empty method, but I wonder the necessity to have a len merge?

Could you provide some more background on how other ecosystem libraries do it?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Length and emptiness checks scan every sealed segment under the shared mutex, causing quadratic work when draining large payloads and blocking senders unnecessarily.

1 open issue
What changed in this PR

Adds receiver-side len and is_empty APIs to bounded and unbounded mpsc and mpmc channels, following the endpoint inspection work in #377.

Changes:

  • Counts queued, unreceived values while excluding held permits and sends waiting for capacity.
  • Includes receiver-local batches in unbounded mpsc counts.
  • Adds API examples, integration tests, and a changelog entry.
File Description
tests-integration/​tests/​mpsc_test/​main.rs Tests reservations, blocked sends, local batches, and draining.
tests-integration/​tests/​mpmc_test/​main.rs Tests queue counts across receiver clones and disconnection.
CHANGELOG.md Documents the new receiver APIs and counting semantics.
asyncband/​src/​mpsc/​unbounded/​receiver.rs Adds observations covering local and shared buffers.
asyncband/​src/​mpsc/​unbounded/​buffer.rs Adds buffer length calculation and assertions.
asyncband/​src/​mpsc/​bounded/​receiver.rs Adds documented queue length and emptiness APIs.
asyncband/​src/​mpmc/​unbounded.rs Exposes documented observations through shared state.
asyncband/​src/​mpmc/​queue.rs Adds shared queue length and emptiness helpers.
asyncband/​src/​mpmc/​bounded.rs Exposes observations excluding capacity reservations.

Review effort: Balanced

Comment thread asyncband/src/mpsc/unbounded/buffer.rs Resolved

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the receiver-side len and is_empty additions.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@FalkWoldmann

Copy link
Copy Markdown
Contributor Author

Fair. The concrete need I have is is_empty: compio's poll driver checks !completed_rx.is_empty() before deciding whether to wait, and I use it the same way to tell whether an event loop is idle. len I only actually use in Debug output and tests. For the ecosystem, tokio has len and is_empty on the mpsc receivers only, async-channel, flume, crossbeam-channel and kanal have len, is_empty, is_full and capacity on both ends. So parity is the only argument for len here, and I'm fine dropping it and keeping just is_empty if you prefer

@tisonkun

tisonkun commented Nov 1, 2026

Copy link
Copy Markdown
Member

Thanks for the context! Keeping the surface minimal makes sense here. I'd prefer to drop len and keep only is_empty on the receivers for now:

  1. is_empty directly covers the event-loop / poll-driver readiness check without introducing the ambiguity between queued messages and reserved capacity (Permits) on bounded channels, and it avoids constraining future lock-free unbounded implementations to maintain an atomic length counter.
  2. In mpsc::unbounded::UnboundedReceiver::is_empty, please short-circuit on the local batch before locking shared (e.g., self.batch.lock().is_empty() && self.shared.lock().buffer.is_empty()), so checking a receiver with buffered local items doesn't contend with senders on the shared mutex.
  3. In the mpsc receiver docs, we can also note that while true may become stale as senders push new values, false guarantees that the next receive on that receiver will find a value because &mut self prevents concurrent receives.

@FalkWoldmann FalkWoldmann changed the title feat(channel): add len and is_empty to mpsc and mpmc receivers feat(channel): add is_empty to mpsc and mpmc receivers Nov 1, 2026

@tisonkun tisonkun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FalkWoldmann You may resolve the conflict so I can merge it later.

I can resolve them myself anyway when it comes to me next time :D

@FalkWoldmann

Copy link
Copy Markdown
Contributor Author

Dropped len and rebased onto main as one commit now that #391 is in, since both touched the same spots. UnboundedReceiver::is_empty checks the local batch first and takes the shared lock only when that's empty, and the mpsc receiver docs say a false result guarantees the next receive finds a value because receiving takes &mut self. I left the mpmc docs at "may become stale as other tasks send or receive", since competing receivers give no such guarantee there. The PR title and the changelog line match now. Heads up, the macos-14 jobs are failing because of GitHub's brownout and that image is unsupported from Nov 2, so CI needs a newer one

@orthur2 orthur2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks good to me.

@orthur2
orthur2 merged commit c37b1a4 into apache:main Nov 1, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants