Frontend Labs
⋯

53. Goroutine stacks and the scheduler, revisited

53.1 Growable stacks

A goroutine starts with a small stack (historically 2KB) and grows by copying to a larger allocation when it would overflow — checked cheaply at function-call prologues. This is why launching a goroutine per connection (Chapters 26, 38) scales to tens of thousands of concurrent connections without the multi-megabyte-per-thread cost a traditional one-thread-per-connection server pays.

53.2 What actually blocks a goroutine (and what doesn't)

Channel operations, mutex waits, and blocking syscalls park a goroutine without consuming an OS thread while parked (Chapter 28.2's syscall detachment). CPU-bound work with no goroutine-yielding operation used to be a scheduling risk before cooperative preemption existed everywhere (Chapter 28.4); today it mostly is not, though a truly pathological tight loop with function inlining that removes preemption checkpoints remains a rare edge case worth knowing about, not a daily concern.

53.3 Real-world example

The reason "spawn 50,000 goroutines to handle 50,000 concurrent WebSocket connections" is a completely normal, load-tested Go architecture — and the equivalent in a thread-per-connection language would need a very large machine or an event-loop rewrite — comes directly from this stack-growth-plus-scheduler design, not from any particular library.


Generated from real-life-golang-guide.md · 8 Oct 2026 16:36