-
Notifications
You must be signed in to change notification settings - Fork 0
16 — The Thread Explosion Problem
Every time a chef gets stuck waiting (blocked), the kitchen manager hires a brand new chef to keep throughput up. Do this enough and the kitchen is overflowing with idle, waiting staff — more costly than helpful.
Heavy use of blocking calls (.sync, DispatchSemaphore.wait()) on concurrent queues can cause GCD's thread pool to keep growing to compensate for blocked threads, leading to excessive memory use and context-switching overhead — this is the "thread explosion problem."
Healthy pool: [👨🍳][👨🍳]
Under load: [👨🍳][👨🍳][👨🍳][💤][💤][💤][💤][💤] ← mostly blocked, still costing resources
// Each of these can tie up a thread waiting, encouraging the pool to grow
for _ in 0..<100 {
DispatchQueue.global().async {
someSemaphore.wait() // blocks a whole thread
doWork()
someSemaphore.signal()
}
}This was a chief motivation for Swift Concurrency's design — its cooperative thread pool is fixed-size, and await suspends the task without blocking a thread, so waiting work doesn't force new threads into existence.
Blocking calls don't just wait — they can make the kitchen hire more chefs than it needs.
GCD's thread pool growth isn't literally unbounded — the system caps it — but even the capped growth can be enough to hurt performance under heavy blocking-call load.
Why is DispatchSemaphore.wait() more dangerous at scale than it looks in a small example?