crossbeam channels¶
Level: 301 · deep dive
One line: Since Rust 1.67 std's mpsc has been built on the design of crossbeam-channel ↗ — same machinery, smaller API — so the reasons left to add the crate are a Receiver you can clone and a select! that waits on several channels at once.
Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The bullets below are the questions the finished page has to answer.
What it has to cover¶
- What 1.67 changed: the release announcement ↗ says the
mpscimplementation was "switched out to be based on crossbeam-channel", with no API changes. So is there any performance reason left to add the crate, and what did std deliberately not take? - Multi-consumer:
crossbeam_channel::ReceiverisClone, so N workers read one channel without theArc<Mutex<Receiver>>that Worker pools needs. std hasstd::sync::mpmc↗, but in Rust 1.98 it is nightly-only (mpmc_channel, issue #126840). select!withrecv,sendanddefault(timeout)arms. The docs say that when several operations are ready at once, "a random one among them is selected" — what does a program that relies on arm order print over a thousand runs?- Zero capacity:
bounded(0)is a rendezvous where a send waits for a receive — and so is std'ssync_channel(0)↗, whose docs call it a "rendezvous channel". The difference people cite is not a difference. - The extra constructors
after,at,tickandnever, each returning only aReceiver— how they turn a timeout or a heartbeat into one moreselect!arm. - Disconnection with many receivers: when does
sendstart returningErr, and when doesrecvon one clone see the channel as closed? crossbeamis a family: the umbrellacrossbeam↗ crate lists channels, work-stealing deques, epoch-based memory management andCachePaddedamong its tools. Which single crate does this page need, and what does depending on the umbrella add to a build?
The trap it exists for¶
Adding crossbeam-channel "because it is faster than std" in code written after 2023, when std has used the same design since 1.67 — or hand-building a shared Arc<Mutex<Receiver>> when the two features that were missing, a cloneable receiver and select!, are exactly what the crate provides.
Where this sits¶
- Channels covers std's semantics —
sendmoves, empty against disconnected, a bound as backpressure, and the keptSender. This page covers only whatcrossbeam-channeladds on top.
See also¶
- Channels — the std API this page is measured against
- Worker pools — the
Arc<Mutex<Receiver>>that a cloneable receiver removes - Actors — one owner with several mailboxes, the case
select!is for - Spawning a thread — the threads on either end
- Adding a dependency — what
cargo add crossbeam-channelwrites - Books — Rust in Action's chapter 10 teaches threads with
crossbeamchannels, and that page pairs it with the two std lessons
If you are coming from another language¶
- Go. This is the crate that makes Rust channels feel like Go's. A Go channel has any number of senders and receivers, which is
crossbeam'sCloneon both ends;selectpicks at random among ready cases, asselect!does —selectchooses at random ↗ andselectwaits on many channels ↗ are the Go pages. An unbufferedmake(chan T)isbounded(0), per An unbuffered send waits for a receiver ↗, andtime.Afteriscrossbeam_channel::after. What stays different is closing: Go closes a channel withclose,crossbeamwhen the last sender drops. - Java.
BlockingQueueis multi-consumer already, andSynchronousQueueis the zero-capacity rendezvous. Java has noselectover queues; the usual substitute is one queue carrying a sum type, which in Rust is anenumon one channel — often simpler thanselect!. - Python.
queue.Queueis multi-consumer, and there is no select across several of them for threads.asyncio.wait(…, return_when=FIRST_COMPLETED)is the nearest thing, and it lives in the async world. - Concepts: select ↗ · unbuffered channel ↗ · bounded channel ↗ · channel ↗
Po polsku¶
Od Rusta 1.67 standardowe mpsc działa w oparciu o projekt crossbeam-channel, więc „szybciej niż std” przestało być argumentem. Zostają dwie rzeczy, których std na stabilnym kanale (stable) nie ma: klonowalny odbiornik (Receiver: Clone, czyli wielu konsumentów — multi-consumer) i makro select!, które czeka na kilka kanałów naraz. Kanał o pojemności zero (rendezvous) nie jest różnicą — sync_channel(0) z biblioteki standardowej działa tak samo.
Szukaj po polsku: kanał wielu producentów i wielu konsumentów · kanał spotkaniowy (rendezvous) · crossbeam channel vs std mpsc · rust select multiple channels · rust mpmc channel stable