Sobes.tech
Middle+

Tell about the concurrency control pattern (GMP) in Go language.

sobes.tech AI

Answer from AI

GMP is a model for scheduling the execution of goroutines in Go, where:

  • G (Goroutine): A lightweight thread of execution, an abstraction over system threads.
  • M (Machine): An OS system thread. It can execute code of one or multiple goroutines.
  • P (Processor): A logical processor representing a context for executing goroutines. Each P is assigned an M, and P contains a local queue of runnable goroutines. The number of P defaults to $GOMAXPROCS (usually the number of CPU cores).

It works as follows:

  1. The scheduler (part of Go's runtime) places new goroutines into the global or local P queues.
  2. An M associated with a P takes a goroutine from the P queue and executes it.
  3. When a goroutine blocks (e.g., waiting for I/O or on a mutex):
    • The M detaches from the current P.
    • The scheduler tries to find another M to take over this P, or creates a new one.
    • The blocked goroutine is placed in a special queue.
    • When the block is released, the goroutine becomes runnable again and returns to the P queue.
  4. When a goroutine exhausts its time quantum or explicitly yields control (rarely), the scheduler may switch the M to another goroutine within the same P.

Advantages of this approach:

  • Efficient utilization of system threads M.
  • Reduced overhead for context switching compared to native OS threads.
  • Load balancing among P via "work stealing" (M can steal a goroutine from another P's queue).

Example of creating a goroutine:

// main.go
package main

import (
	"fmt"
	"time"
)

func worker(id int) {
	fmt.Printf("Worker %d starting\n", id)
	time.Sleep(time.Second) // Illustration of blocking/busy state
	fmt.Printf("Worker %d finished\n", id)
}

func main() {
	for i := 1; i <= 5; i++ {
		go worker(i) // Create a new goroutine
	}

	time.Sleep(time.Second * 2) // Wait for goroutines to finish
}