DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.

← Back to Questions
MediumTheory

Goroutines: Scheduling, Blocking, and Best Practices

15 views

Problem Statement

Understand how goroutines are scheduled, what causes blocking, and best practices for managing concurrent workloads.

Key Interview Questions

Q1: What is the M:N scheduler?

Answer: Go multiplexes M goroutines onto N OS threads. This allows millions of goroutines on a few threads.

Q2: What is a "P" in the GMP model?

Answer: Processor/Context. It holds the local run queue and resources needed to execute goroutines. Number of Ps = GOMAXPROCS.

Q3: Why is a goroutine stack only 2KB vs 1-8MB for OS threads?

Answer: Goroutine stacks grow dynamically. They start small and expand as needed (up to 1GB). OS thread stacks are fixed at creation.

Q4: What happens when a goroutine does a blocking syscall?

// During blocking syscall (file I/O, etc.):
// 1. M (thread) blocks with the goroutine
// 2. P detaches from M
// 3. P finds/creates new M to run other goroutines
// 4. When syscall returns, G is re-queued

Q5: What is "Work Stealing"?

Answer: When a P's local run queue is empty, it steals half the goroutines from another P's queue to stay busy.

Q6: Is the Go scheduler preemptive?

Answer: - Pre-1.14: Cooperative (required function calls for preemption) - Go 1.14+: Asynchronously preemptive (uses signals to preempt tight loops)

Q7: How do you limit concurrent goroutines?

// Semaphore pattern
sem := make(chan struct{}, 10) // Max 10 concurrent

for _, item := range items {
    sem <- struct{}{} // Acquire
    go func(item Item) {
        defer func() { <-sem }() // Release
        process(item)
    }(item)
}

Q8: What is GOMAXPROCS?

import "runtime"

// Get current value
n := runtime.GOMAXPROCS(0)

// Set to 4 Ps
runtime.GOMAXPROCS(4)

// Default: runtime.NumCPU()

Answer: Limits number of active Ps (logical processors). Defaults to number of CPU cores.

Q9: The Loop Variable Trap

// BUG: All goroutines print same value
for i := 0; i < 5; i++ {
    go func() {
        fmt.Println(i) // Captures reference!
    }()
}

// FIX 1: Pass as argument
for i := 0; i < 5; i++ {
    go func(i int) {
        fmt.Println(i)
    }(i)
}

// FIX 2: Go 1.22+ - loop variables are per-iteration

Sample Test Cases

Case 1
Input
go func() { fmt.Println("hello") }()
Expected Output
Prints hello asynchronously
Case 2
Input
goroutine calls blocking syscall
Expected Output
Scheduler switches to another G

No solutions yet

Be the first to share a solution for this question.

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Stats

Views
15
Likes
0
Solutions
0
Comments
0

Category

Backend Engineering

Languages

Go