rust 40 lines · 7 steps

A round-robin worker pool in Rust

Spawns a fixed set of worker threads, each with its own channel, and spreads tasks across them with an atomic counter.

Explained by highlit
1use std::sync::atomic::{AtomicUsize, Ordering};
2use std::sync::Arc;
3use std::thread;
4 
5pub struct RoundRobin<T> {
6 workers: Vec<crossbeam_channel::Sender<T>>,
7 next: AtomicUsize,
8}
9 
10impl<T: Send + 'static> RoundRobin<T> {
11 pub fn new<F>(count: usize, handler: F) -> Arc<Self>
12 where
13 F: Fn(usize, T) + Send + Sync + Clone + 'static,
14 {
15 let mut workers = Vec::with_capacity(count);
16 
17 for id in 0..count {
18 let (tx, rx) = crossbeam_channel::unbounded::<T>();
19 let handler = handler.clone();
20 thread::spawn(move || {
21 for task in rx {
22 handler(id, task);
23 }
24 });
25 workers.push(tx);
26 }
27 
28 Arc::new(Self {
29 workers,
30 next: AtomicUsize::new(0),
31 })
32 }
33 
34 pub fn dispatch(&self, task: T) {
35 let idx = self.next.fetch_add(1, Ordering::Relaxed) % self.workers.len();
36 if self.workers[idx].send(task).is_err() {
37 eprintln!("worker {idx} channel closed, dropping task");
38 }
39 }
40}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Giving each worker its own channel avoids contention on a single shared queue.
  2. 2An atomic counter with modulo arithmetic distributes work evenly without a lock.
  3. 3Handling a closed channel on send keeps the dispatcher from panicking when a worker dies.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A round-robin worker pool in Rust — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code