Sobes.tech
Middle+

Parla del pattern di gestione della concorrenza (GMP) nel linguaggio Go.

sobes.tech AI

Risposta dell'AI

GMP è un modello di pianificazione dell'esecuzione delle goroutine in Go, dove:

  • G (Goroutine): Un thread leggero di esecuzione, un'astrazione sopra i thread di sistema.
  • M (Machine): Un thread del sistema operativo. Può eseguire il codice di una o più goroutine.
  • P (Processor): Un processore logico, che rappresenta un contesto per l'esecuzione delle goroutine. A ogni P è assegnato un M, e P contiene una coda locale di goroutine in stato runnable. Il numero di P di default è $GOMAXPROCS (solitamente il numero di core del processore).

Funziona così:

  1. Lo scheduler (parte del runtime di Go) mette le nuove goroutine nelle code globali o locali di P.
  2. Un M, associato a un P, prende una goroutine dalla coda di P e la esegue.
  3. Quando una goroutine si blocca (ad esempio, in attesa di I/O o su un mutex):
    • M si dissocia dal P corrente.
    • Lo scheduler cerca un altro M per occupare quel P, o ne crea uno nuovo.
    • La goroutine bloccata viene messa in una coda speciale.
    • Quando il blocco viene rimosso, la goroutine torna in stato runnable e ritorna nella coda di P.
  4. Quando la goroutine esaurisce il suo quantum di tempo o cede esplicitamente il controllo (raramente), lo scheduler può cambiare M con un'altra goroutine nello stesso P.

Vantaggi di questo approccio:

  • Uso efficiente dei thread di sistema M.
  • Riduzione dei costi di cambio di contesto rispetto ai thread nativi del sistema operativo.
  • Bilanciamento del carico tra P tramite il meccanismo di "work stealing" (M può rubare una goroutine dalla coda di un altro P).

Esempio di creazione di una goroutine:

// main.go
package main

import (
	"fmt"
	"time"
)

func worker(id int) {
	fmt.Printf("Worker %d starting\n", id)
	time.Sleep(time.Second) // Illustrazione di blocco/occupazione
	fmt.Printf("Worker %d finished\n", id)
}

func main() {
	for i := 1; i <= 5; i++ {
		go worker(i) // Creiamo una nuova goroutine
	}

	time.Sleep(time.Second * 2) // Aspettiamo che le goroutine finiscano
}