#queue #unbounded #spsc #consumer #performance #buffer #size

nightly unbounded-spsc

An unbounded spsc queue built from bounded_spsc_queues

8 releases

0.1.9 May 6, 2023
0.1.8 Jan 6, 2023
0.1.7 Mar 21, 2022
0.1.6 Aug 27, 2020
0.1.3 Apr 30, 2018

#882 in Concurrency

Download history 13/week @ 2024-02-26 8/week @ 2024-03-11 1/week @ 2024-03-18 137/week @ 2024-04-01

146 downloads per month
Used in apis

Apache-2.0

46KB
1.5K SLoC

unbounded_spsc

An "unbounded" extension of bounded_spsc_queue.

This crate provides an unbounded SPSC queue with asynchronous sends, using bounded_spsc_queue for the internal queue. This provides better performance and cache coherence than the linked-list queue used in the standard std::sync::mpsc::channel.

Besides being bounded, bounded_spsc_queue itself only provides spin-wait for blocking recv (blocking when buffer is empty), so the blocking-wait code found in the standard library is adapted here to provide a more CPU-friendly blocking mechanism, both with and without timeout. This code is essentially lock-free; there are no mutexes or condvars involved.

Note that bounded_spsc_queue does not support zero-size message types (such as unit type ()), and will crash with an unspecified error; here we check for zero-size and panic! with an error message.

Sends are always asynchronous; if the underlying buffer is full, a new buffer is created that is twice the size of the previous buffer, and sent to the consumer by means of a standard asynchronous mpsc channel. Currently there are no mechanisms for specifying initial capacity (hard-coded to 128) or shrinking.

Synchronous send (blocking when buffer is full) is not provided here: for that use either bounded_spsc_queue directly (spin-wait) or a standard std::sync::mpsc::sync_channel (block-waiting; uses a vector-backed buffer internally).

Also taken from the standard library is the (unstable) implementation of the select! macro and related functionality that allows waiting on multiple receivers. As noted in the original implementation, this code is sub-optimal since it involves some allocations, and does not implement any kind of "fairness" protocol-- see https://github.com/rust-lang/rust/issues/27800.

Dependencies

~255KB