[rust-dev] Unbounded channels: Good idea/bad idea?
bascule at gmail.com
Wed Dec 18 18:29:01 PST 2013
As someone who knows a lot of people who use Erlang in production (Erlang
has unbounded mailboxes), and the maintainer of my own actor-based
concurrency framework (Celluloid, which started with unbounded mailboxes
and is in the process of moving to bounded ones), I have come to the Hard
Won Knowledge(TM) that unbounded queues/mailboxes/channels are a bad idea.
In terms of production users of these sorts of systems, my personal
experience is that nobody likes unboundedness and most have experienced
some sort of production outage because of it. This isn't just a minor
nitpick. This is the sort of decision that makes or breaks the reliability
of systems under load.
The main problem with unboundedness is that users systems based on
unbounded queues fail to adequately build mechanisms for providing
backpressure into their code. They then start flooding their systems with
messages, and get confused why they're performing so poorly when the answer
is they have a huge backlog of unprocessed messages. Processes overloaded
with too many messages will slow down and grow in memory until they
eventually exhaust system resources and crash.
Adding bounds to a channel doesn't require that sends block, and I think
Rust is doing the Right Thing(TM) here in regard to non-blocking sends and
I would never ask you to change that. There are other options for bounding
channels which don't involve a blocking send though:
1) Drop messages on the floor: This falls into the category of "at most
once" message semantics that actor systems are typically described as
having (although there's a fun discussion about this right now on the friam
mailing list). My personal opinion is that systems that can tolerate the
loss of messages are more robust by design
2) Crash the sender: This works similarly to the above in that it results
in the messages being discarded, but can loop in Erlang-style fault
tolerance to recover from an overloaded system. I definitely find this less
preferable than simply dropping messages on the floor though. This is a
particularly invasive option that I think doesn't translate well to
3) Make sends to a full channel an error: I'm really not a fan of this
option at all but I'm listing it for completeness. We could make everyone
check every message send for success. Ick. No thanks.
Bounded channels offer a lot of advantages over unbounded ones, IMO.
Fixed-size data structures confer a natural performance advantage over
elastic ones that need to be resized to accomodate growing numbers of
messages. Depending on what data structure you use, you either take an
up-front performance hit to provide variable capacity, or take an invisible
performance hit whenever you hit some cap and need to resize. Adding a
bound makes it easier to reason about the use cases and requirements and
will generally allow you to leverage better data structures (e.g. ring
buffers) that will confer maximum performance.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Rust-dev