| Crates.io | spillway |
| lib.rs | spillway |
| version | 1.0.0-pre.2 |
| created_at | 2025-12-16 01:27:33.447568+00 |
| updated_at | 2026-01-09 01:22:18.631061+00 |
| description | High throughput, safe, async MPSC channel |
| homepage | |
| repository | https://github.com/kvc0/protosocket |
| max_upload_size | |
| id | 1987043 |
| size | 26,395 |
A high-throughput multi-producer, single-consumer (MPSC) channel.
This channel was made to relieve a performance bottleneck in the
protosocket ecosystem.
tokio_test::block_on(async {
use spillway::channel;
let (sender_1, mut receiver) = channel();
// Send is synchronous
sender_1.send(1);
// Cloning a sender results in a different cursor with a separate order
let sender_2 = sender_1.clone();
// interleave messages to illustrate ordering
sender_2.send(2);
sender_1.send(3);
sender_2.send(4);
// Only order per-sender is guaranteed
assert_eq!(Some(1), receiver.next().await, "sender 1 is consumed first");
sender_1.send(5);
assert_eq!(Some(3), receiver.next().await, "sender 1 had 1-3-5, but 5 is in another delivery batch.");
assert_eq!(Some(2), receiver.next().await, "sender 2 is consumed next");
assert_eq!(Some(4), receiver.next().await);
let sender_3 = sender_1.clone();
sender_3.send(6);
assert_eq!(Some(6), receiver.next().await, "yes, sender_1 sent 5 first, but lanes are serviced round-robin.");
assert_eq!(Some(5), receiver.next().await, "and finally, we made it back around to 5");
})
Many MPSC channel implementations guarantee ordering across senders, when
you externally guarantee happens-before. They might not claim it, but their
implementations often tend to be fancy OCC loops with final ordering
determined at send() time.
Spillway ordering is only determined per-sender at send() time. This is
how many senders can send with very little contention between them.
For each Sender, its messages will appear in order to the Receiver. Any
other Sender's messages may appear before, between, or after this Sender's
messages. But each Sender's messages will appear only in the order the messages
were submitted to the Sender.
There's no unsafe code in this channel. It's basically a Vec<Mutex<VecDeque<T>>>.
Each Sender gets an index i at creation time, and that i is valid for the outer
Vec. That decides which Mutex will block this Sender, and which "chute" or "shard"
or "lane" will order the messages from this Sender.
The Receiver holds a buffer of messages. When it's empty, it advances to the next
chute with messages in it, and swaps its empty buffer for the chute's messages. It
then resumes fulfilling next() by pop_front() on the current buffered VecDeque<T>.
In benchmark tests with various processor architectures, the
channel bench on this repository shows the tokio mpsc channel
producing around 5-10mhz throughput. The spillway channel outperforms
typically by a factor of around 20x. For example, on my older m1 macbook:
| tokio | spillway | |
|---|---|---|
| throughput | 4.5mhz | 92.7mhz |
| latency | 219.4ns | 10.8ns |
| std deviation | 16.6ns | 2.5ns |