1 unstable release

0.1.0 Dec 17, 2023

#939 in Concurrency

Download history 6/week @ 2024-09-08 1/week @ 2024-09-15 9/week @ 2024-09-22 23/week @ 2024-09-29 96/week @ 2024-10-06 67/week @ 2024-10-13 40/week @ 2024-10-20 78/week @ 2024-10-27 99/week @ 2024-11-03 128/week @ 2024-11-10 97/week @ 2024-11-17 74/week @ 2024-11-24 110/week @ 2024-12-01

409 downloads per month

MIT license

16KB
239 lines

GitHub Repo stars Crates.io docs.rs GitHub Workflow Status (with event)

High throughput and simple buffered MPSC channel implementation.

bufchan is a MPSC channel implementation that prioritises sender throughput over receiver latency. It uses local buffers to avoid accessing the shared state, only sending items as a batch once a threshold is reached. This implementation prioritises sender throughput, for example a heavy computation task where one wants to keep the compute threads as unblocked as possible.

bufchan is also very simple. The channel implementation is around 100 lines of code, and uses no unsafe. I would encourage users to read through the source code, it is heavily commented and a great way to understand channels!

Benchmarks

A benchmark setup to measure throughput is constructed where a certain number of tasks do some non-trivial and non-constant work. The tasks are parallelised, with each result getting sent with the various channel implementation offerings. The int benchmarks are sending 32-bit integers, the other two benchmarks send an array of various sizing.

bench                 fastest       │ slowest       │ median        │ mean 
├─ int                              │               │               │       
│  ├─ bufchan         36.43 ms      │ 44.15 ms      │ 36.88 ms      │ 37.28 ms
│  ├─ bufchan_buf0    36.5 ms       │ 140.1 ms      │ 38.49 ms      │ 39.6 ms
│  ├─ crossbeam       37.66 ms      │ 42.02 ms      │ 39.14 ms      │ 39.26 ms
│  ├─ flume           122.9 ms      │ 137.9 ms      │ 125.5 ms      │ 127.5 ms
│  ├─ kanal           38.55 ms      │ 49.36 ms      │ 41.54 ms      │ 41.75 ms
│  ╰─ std_mpsc        37.21 ms      │ 44.13 ms      │ 40.43 ms      │ 40.19 ms
├─ non_copy_24bytes                 │               │               │        
│  ├─ bufchan         37.08 ms      │ 137.9 ms      │ 37.96 ms      │ 39.15 ms
│  ├─ bufchan_buf0    36.89 ms      │ 141.1 ms      │ 39.19 ms      │ 41.45 ms
│  ├─ crossbeam       125.9 ms      │ 138.1 ms      │ 128.5 ms      │ 130.5 ms
│  ├─ flume           124.1 ms      │ 144.5 ms      │ 128 ms        │ 130.5 ms
│  ├─ kanal           40.42 ms      │ 46.93 ms      │ 42.78 ms      │ 42.93 ms
│  ╰─ std_mpsc        123.6 ms      │ 144.7 ms      │ 127.7 ms      │ 130.2 ms
╰─ non_copy_256bytes                │               │               │         
   ├─ bufchan         37.4 ms       │ 48.61 ms      │ 38.83 ms      │ 39.14 ms
   ├─ bufchan_buf0    37.84 ms      │ 46.2 ms       │ 40.85 ms      │ 40.78 ms
   ├─ crossbeam       125.7 ms      │ 139.8 ms      │ 128.5 ms      │ 130.5 ms
   ├─ flume           124.6 ms      │ 140.2 ms      │ 126.9 ms      │ 128.8 ms
   ├─ kanal           45.76 ms      │ 58.58 ms      │ 48.37 ms      │ 48.61 ms
   ╰─ std_mpsc        123.7 ms      │ 143.6 ms      │ 126.8 ms      │ 128.7 ms

Caveats

It must be stressed that this is a buffered channel. A single send call is likely to not trigger the complementing recv to wakeup. All messages are guaranteed to reach Receiver, but the latency of individual messages is not consistent. For long-lived Senders that are slow to produce, lowering the buffer size, or manually calling flush can ensure messages get to the receiver.

Dependencies

~0.4–5MB
~11K SLoC