#286 Jul 28, 2026

286. available_parallelism — Stop Hardcoding Your Worker Count

That let workers = 8; in your thread pool is wrong on almost every machine but yours. std can tell you how many threads the program can actually run at once — no crate needed.

The channel series (bites 281285) kept spawning workers without ever asking the obvious question: how many? Hardcoding a number over-subscribes small machines and wastes big ones. std::thread::available_parallelism (stable since 1.59) gives the real answer:

1
2
3
4
5
6
7
use std::thread;

let workers = thread::available_parallelism()
    .map(|n| n.get())
    .unwrap_or(1);

assert!(workers >= 1);

It returns io::Result<NonZeroUsize> — two deliberate choices in one signature. The Result is because some platforms can’t answer; .unwrap_or(1) degrades gracefully. The NonZeroUsize is a guarantee: on success the count is never zero, so dividing work by it can’t panic:

1
2
3
4
5
6
let data: Vec<u32> = (0..100).collect();

// never a divide-by-zero, workers >= 1
let chunk = data.len().div_ceil(workers);
let batches = data.chunks(chunk).count();
assert!(batches <= workers);

Why not just count cores?

Because the answer isn’t “how many cores does the CPU have” — it’s “how many can this process use,” which can be far smaller:

  • cgroup CPU quotas (Linux): a container capped at 2 CPUs on a 64-core host reports 2, not 64
  • process affinity masks: pinned to 4 cores, you get 4
  • SMT: hyperthreads count, so an 8-core/16-thread CPU typically reports 16

A naive core count in a Kubernetes pod spawns 64 threads to fight over 2 CPUs. available_parallelism reads the quota and sizes the pool right.

Two caveats: the value is a snapshot (quotas can change mid-run), and it’s a hint for CPU-bound work — an I/O-bound pool may justifiably want more threads than cores.

← Previous 285. try_iter — The Drain Loop You Wrote This Morning, as One Line Next → 287. thread::Builder — Name Your Workers So Panics Tell You Who Died