03 / 10

How does Go's GMP scheduler work and how does it affect concurrency design?

The GMP model (Goroutines, OS threads, Processors) is Go's runtime scheduler that multiplexes goroutines onto OS threads using work-stealing, enabling massive concurrency with minimal overhead.

GMP components
  1. 1

    G (Goroutine): the unit of work with its own stack and state

  2. 2

    M (Machine/OS thread): the entity that actually executes code on the CPU

  3. 3

    P (Processor): a logical processor with a local run queue, limited by GOMAXPROCS

  4. 4

    Each P can run one G at a time on one M — GOMAXPROCS controls parallelism, not concurrency

  5. 5

    Global run queue: overflow queue when local P queues are full

Scheduling behaviors
  1. 1

    Work stealing: idle P steals goroutines from busy P's local queue — automatic load balancing

  2. 2

    Preemption: goroutines are preempted at function calls and loop back-edges (Go 1.14+) — no starvation

  3. 3

    Blocking syscall: when G blocks on a syscall, P detaches from M and attaches to a new M so other goroutines keep running

  4. 4

    Network I/O: Go's netpoller parks goroutines awaiting I/O without blocking an OS thread

GOMAXPROCS and scheduler implications
Difficulty: 7/10
Topics: GMP scheduler, GOMAXPROCS, goroutine scheduling

Scenario Questions

0-2 years experience
  1. 1

    If you launch 1000 goroutines that each perform a quick CPU‑bound calculation, how many OS threads do you expect Go to use by default, and why?

  2. 2

    What happens if you call runtime.GOMAXPROCS(1) in a program that spawns many goroutines? How does that affect scheduling?

  3. 3

    When a goroutine blocks on a channel send, what does the Go scheduler do with its underlying M?

2-5 years experience
  1. 1

    You notice a latency spike in a service that uses a worker pool of goroutines processing requests. How would you investigate whether the GMP scheduler is a bottleneck?

  2. 2

    Explain why increasing GOMAXPROCS sometimes doesn't improve throughput in a Go microservice, and what scheduler behavior you would look at.

  3. 3

    During a load test, you see many goroutines stuck in 'syscall' state. How does the scheduler handle syscalls, and what changes could you make to mitigate the issue?

5-8 years experience
  1. 1

    Design a high‑throughput pipeline that mixes CPU‑bound and I/O‑bound stages. How would you configure GOMAXPROCS and possibly use runtime.LockOSThread to influence the GMP scheduler for optimal performance?

  2. 2

    When migrating a legacy C++ service to Go, you need to preserve its thread‑affinity guarantees. How would you work with the GMP scheduler to ensure certain goroutines stay on specific OS threads?

  3. 3

    Explain the trade‑offs of using many short‑lived goroutines versus a fixed pool of workers in a system that must handle millions of concurrent connections, considering the scheduler’s work‑stealing and P‑local runqueues.

8+ years experience
  1. 1

    At a company‑wide level, you are deciding whether to adopt Go for a new distributed system that requires strict real‑time latency. How would the GMP scheduler influence that decision, and what architectural mitigations would you propose?

  2. 2

    Your organization has multiple services written in Go that share a common library which spawns background goroutines. Over time, you observe increased CPU contention. How would you redesign the library or runtime configuration to reduce scheduler contention across services?

  3. 3

    If you need to run Go services on a heterogeneous cluster where some nodes have many cores and others have few, how would you design a deployment strategy that adapts GOMAXPROCS and leverages the scheduler to maintain consistent performance?

Follow-up Questions

  • Can you give an example of when you’d manually lock a goroutine to an OS thread?
  • How does the scheduler decide to steal work from another P?
  • What impact does a blocking syscall have on the number of M’s in the system?