Sobes.tech
Middle+

Tell me about the Go scheduler. How does it work with blocking operations?

sobes.tech AI

Answer from AI

The Go scheduler (runtime scheduler) manages the execution of goroutines — lightweight threads that Go creates for concurrent code execution. It uses an M:N model, where M is the number of system threads (OS threads), and N is the number of goroutines.

Main components:

  • G (goroutine) — a goroutine object.
  • M (machine) — a system thread of the OS.
  • P (processor) — a logical processor that connects G and M.

The scheduler distributes goroutines to available P's, which are run on M.

Handling blocking operations: If a goroutine performs a blocking operation (e.g., a system call, network read), the scheduler can:

  • Detach M from the current P and start another M with a different P to avoid blocking other goroutines.
  • Launch a new system thread (M) if all M's are blocked, to ensure other goroutines can run.

Thus, blocking operations do not block the entire scheduler, only the specific OS thread, and the runtime tries to compensate by creating new threads or redistributing goroutines.

Example:

func main() {
    go func() {
        time.Sleep(time.Second) // blocking operation
        fmt.Println("Goroutine 1")
    }()
    go func() {
        fmt.Println("Goroutine 2")
    }()
    time.Sleep(2 * time.Second)
}

Here, despite the first goroutine being blocked, the second will execute without delays thanks to the scheduler.