Goroutine Vs Thread Scenario
Fast recall
Quick revision
Core answer
Whether you understand Goroutine Vs Thread Scenario beyond memorized syntax.
Giving a definition without explaining a practical trade-off.
Connect the concept to a small production example and state its complexity or failure mode.
Interview-ready guide
Interview answer
The scenario numbers:
func handler(w http.ResponseWriter, r *http.Request) {
// Each request IS a goroutine (net/http spawns one per connection)
data, err := slowService(r.Context()) // this blocks the GOROUTINE, not the thread
json.NewEncoder(w).Encode(data)
}
http.ListenAndServe(":8080", mux)
// 10,000 concurrent requests:
// - 10,000 goroutines (2KB each = ~20MB — fine)
// - GOMAXPROCS OS threads (16 cores = 16 threads actually RUNNING Go code)
// - Blocked-on-I/O goroutines park (the thread handles others)
// - The DB and the downstream service see the bottleneck, not the serverThe scheduler's mechanics for this scenario: 10,000 G (goroutines) distributed across 16 P (scheduler contexts, one per core). Each P has a local run queue. A goroutine blocking on the DB call parks in the network poller — the M (thread) it was running on picks the next G from the P's queue. The 16 threads are always busy with the goroutines that are actually runnable.
The contrast with thread-per-request (Java's classic model / C's): 10,000 threads × 1MB stack = 10GB reserved; context-switching across 10,000 threads = the scheduler thrash; the OS caps (ulimit) hit far earlier. The goroutine model makes the concurrency level a non-issue — the SERVER's bottleneck moves to where it should be (the DB, the downstream).
The genuine limits to name in an interview: the downstream resources. 10,000 concurrent requests = 10,000 DB connections (the DB pool — max 25 connections with queuing), 10,000 open files (the fd limit), 10,000 DNS lookups. Go removes the language-level limit; the system's other limits remain.
Goroutine Vs Thread Scenario
Direct Answer
One goroutine per connection (~2KB each = ~20MB for 10k) — Go's scheduler multiplexes them onto GOMAXPROCS OS threads (cores). Requests that block on I/O park their goroutine (the thread moves on); computation runs in parallel across cores.
Deep Dive & Architecture
The scenario's three states per goroutine, and where they live:
- RUNNING (on a thread) — 16 at a time (GOMAXPROCS)
- RUNNABLE (in a P's queue) — waiting for a free thread
- BLOCKED (parked) — on the network poller (I/O), on a channel, on a mutex, on a timer
The 10,000-request distribution: at any instant, ~16 RUNNING (the cores), most BLOCKED (waiting on the DB/downstream), a few RUNNABLE (just-woken responses). The scheduler's work: wake the right goroutines when their I/O completes (the netpoller's event loop) — the efficiency that makes this model work.
The GOMAXPROCS question (the follow-up): more Ps than cores doesn't help (the cores are the parallelism ceiling); fewer Ps than cores underuses (deliberate throttling — the container-aware GOMAXPROCS story, where Go 1.25 reads cgroup CPU limits — the kernel scheduling composes with Go's).
Common Mistakes & Pitfalls
Giving a definition without explaining a practical trade-off.
Check your understanding
Answer these without looking back at the article.
- When would you use Goroutine Vs Thread Scenario in a real project?
- What is a common mistake when using Goroutine Vs Thread Scenario?
- How would you compare Goroutine Vs Thread Scenario with an alternative?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.