In this lesson, you will learn how to implement the "Fan-Out" pattern to distribute a single message to multiple independent listeners simultaneously.
The Fan-Out Pattern
When building concurrent systems, you often need to notify a group of subscribers about a state change or an event. While Multi-Producer Multi-Consumer (MPMC) channels exist, they typically consume the message—once one receiver pulls the data, it's gone. Broadcasting, by contrast, ensures every subscriber receives a copy of the notification.
In Rust, the most efficient way to achieve this without external crates is to manage a collection of senders. When the publisher produces a message, it iterates through its list of active senders and dispatches the data to each one.
Implementation Illustration
To broadcast effectively, we use a vector of MPSC senders. This allows the publisher to maintain a "subscriber group" that it can push updates to whenever an event occurs.
use std::sync::mpsc;
use std::thread;
fn main() {
let mut subscribers = Vec::new();
// Create 3 subscribers
for i in 0..3 {
let (tx, rx) = mpsc::channel();
subscribers.push(tx);
thread::spawn(move || {
while let Ok(msg) = rx.recv() {
println!("Subscriber {} received: {}", i, msg);
}
});
}
// Broadcast a message to all subscribers
let message = "System Update: Syncing nodes...";
for tx in &subscribers {
let _ = tx.send(message.to_string());
}
}
Critical Considerations
When implementing this, keep three things in mind:
- Fault Tolerance: If a subscriber thread panics or shuts down, the sender will return an error when attempting to
send. In a production system, you should monitor these results and remove disconnected senders from yoursubscribersvector to prevent stale memory. - Backpressure: Since each channel has its own buffer, a slow subscriber might cause the publisher to block if you use synchronous channels. Ensure your buffering strategy matches your throughput needs.
- Ownership: Since you are broadcasting a single piece of data to many, you must either clone the data for each sender or wrap the data in an
Arcto share it cheaply across threads without deep copying.
Key Takeaway: Broadcasting is achieved by maintaining a collection of individual communication channels, allowing you to iterate and propagate state updates to multiple subscribers in a controlled, thread-safe manner.