feat(spmc): add competing queues - #305
Open
mxsm wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Add opt-in bounded and unbounded
asyncband::spmcqueues for distributing work from one producer to competing consumers. Senders are non-cloneable and require&mut self; receivers are cloneable, with each consumed value delivered to exactly one receiver.Reuse the private competing-consumer core shared with MPMC, preserving strict bounded capacity, synchronous unbounded sends, targeted notifications, cancellation handoff, and draining after sender disconnection.
Cover the public capability constraints with compile-fail tests and exercise delivery, cancellation, disconnection, backpressure, and concurrent 1P/8C consumption.
Add reproducible 1P/1C–1P/8C benchmarks against Asyncband MPMC, async-channel, and flume, with methodology and measurements in
benchmarks/ecosystem/spmc/README.md.Fixes feat(spmc): add a competing queue #212.
Validation
cargo x test: 562 tests and doctests passed, including 18 SPMC tests and five compile-fail checks.cargo x check: feature matrix passed, including standalonespmc.cargo x miri: 140 tests passed, including 17 SPMC tests.cargo x bench: full suite passed; three additional serial SPMC runs used 100 samples per case.cargo x lint: Clippy, rustfmt, Taplo, and typos passed; Hawkeye is blocked by the Windows checkout of the existingasyncband/MIGRATE.mdsymlink as a regular file. Targeted header checks for the added and moved source files passed.Performance report
Measured on 2026-09-11 with an Intel Core i7-11700K (8 cores / 16 logical processors), 64-bit Windows 11 Pro 10.0.26200, Rust 1.96.1 (
31fca3adb,x86_64-pc-windows-msvc), and the default optimized bench profile. The implementation is based onmainat8204e14. Peer versions: async-channel 2.5.0 and flume 0.12.0; runtime: Tokio 1.53.1; harness: Divan 0.1.21.Each sample transfers 16,384
usizevalues from one producer to 1, 2, 4, or 8 competing consumers; bounded capacity is 64. The sender moves into one task without cloning or an added synchronization wrapper. Consumers drain until disconnection without fixed quotas, and each sample checks the total count and checksum. Queue and runtime construction are outside the measured region; data operations, disconnection, and task completion are inside.The table reports the median of three run medians, in milliseconds per batch, from three serial runs of 100 samples per case with one batch per sample. No builds or tests ran alongside the measurements. Lower elapsed time is better.
currentdenotes Tokio current-thread;4denotes four worker threads. MPMC uses Asyncband's shared core with one producer. The peer ratio is SPMC time divided by the faster of async-channel and flume, calculated before rounding.The largest sustained gap is unbounded 1P/8C with four workers: 10.360 ms versus async-channel at 2.667 ms (3.88x). The same-core MPMC baseline takes 9.824 ms, about 5% less time than SPMC. Both serialize storage and endpoint state under a mutex and use semaphore-backed notifications; SPMC adds no extra queue lock or per-message allocation over MPMC. Together with the deterministic eight-waiter test verifying one ordinary notification and cancellation handoff, this suggests shared storage/waiter contention. This is an inference from code and measurements, not a lock profile. The gap above 3x remains a performance limitation; no measured topology reaches the 10x rejection threshold from #208 on this host.
Unbounded sends are synchronous for all implementations, so the producer can fill the queue before consumers run on a current-thread executor. Those rows measure draining rather than parallel consumer contention; use the four-worker results and targeted-wakeup tests to assess 1P/8C behavior. These measurements support core reuse on this host and do not establish performance across platforms or workloads.
Reproduce the repository benchmark suite with:
For the focused measurements, run
cargo x bench --no-run, then execute the ecosystem benchmark binary printed by Cargo with--bench --color never --sample-count 100 'spmc::'three times serially. The full methodology and recorded results are also inbenchmarks/ecosystem/spmc/README.md.