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:
- The scheduler (part of Go's runtime) places new goroutines into the global or local P queues.
- An M associated with a P takes a goroutine from the P queue and executes it.
- 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.
- 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
}