This is something I built for my own use, as a reference I can use to remember some of the properties of the Rust channel implementations I use most often.

Which channels implement fallible send? Which one implements an async sender and blocking receiver? What do I lose if I make my channel bounded size? These are the questions I ask myself when picking out an mpsc channel implementation.

Rust Logo

Do I care about performance? Yes. But I generally assume that all of these channels are in use in a lot of environments, and have been benchmarked a hundred ways, and generally have pretty good performance and mostly lock-free operation (except possibly when resizing unbounded channels).

Sending §

growingblockingfallibleasync
std sync_channelsendtry_send
std channelsend
tokio channelblocking_sendtry_sendsend
tokio unbounded_channelsend
crossbeam boundedsendtry_send
crossbeam unboundedsend1try_send

Receiving §

blockingfallibleasyncclone
std sync_channelrecvtry_recvno
std channelrecvtry_recvno
tokio channelblocking_recvtry_recvrecvno
tokio unbounded_channelblocking_recvtry_recvrecvno
crossbeam boundedrecvtry_recvyes 2
crossbeam unboundedrecvtry_recvyes 2

Notes:

1

crossbeam unbounded() returns the same Sender type as bounded(); that Sender::send is documented as "blocks the thread until..." so while I think the unbounded send will never block, that documentation is a bit unclear.

2

I'm not certain that being able to clone a crossbeam Receiver makes the channel a true MPMC channel, but it's a useful property nonetheless.

3

I've only considered mpsc channels, not broadcast, oneshot, watch, or other channel variants. These can be interesting and useful, but are out of scope for this table.

4

I also haven't considered implementations that aren't lock-free in the hot path. Implementations that are a Mutex<VecDeque<T>> in a trenchcoat may have acceptable performance for some workloads, but they are not directly comparable to the data structures in this table.

Cheers! Good luck with your Rust projects.