Skip to content

16 — The Thread Explosion Problem

rebeloper edited this page Jul 12, 2026 · 1 revision

🍽️ Intuition

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.

🧠 What It Means In Swift

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."

📊 ASCII Diagram

Healthy pool:   [👨‍🍳][👨‍🍳]
Under load:     [👨‍🍳][👨‍🍳][👨‍🍳][💤][💤][💤][💤][💤]  ← mostly blocked, still costing resources

💻 Tiny Swift Example

// 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()
    }
}

🔄 vs. Swift Concurrency

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.

🧸 Memory Sentence

Blocking calls don't just wait — they can make the kitchen hire more chefs than it needs.

⚠️ Analogy Limit

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.

✅ Check Your Understanding

Why is DispatchSemaphore.wait() more dangerous at scale than it looks in a small example?

Clone this wiki locally