Middle+
Opowiedz o wzorcu zarządzania współbieżnością (GMP) w języku Go.
sobes.tech AI
Odpowiedź od AI
GMP to model planowania wykonywania goroutine w Go, gdzie:
- G (Goroutine): Lekki wątek wykonawczy, abstrakcja nad wątkami systemowymi.
- M (Machine): Wątek systemu operacyjnego. Może wykonywać kod jednej lub wielu goroutine.
- P (Processor): Logiczny procesor, reprezentujący kontekst do wykonywania goroutine. Każdemu P przypisany jest M, a P zawiera lokalną kolejkę goroutine w stanie runnable. Liczba P domyślnie to
$GOMAXPROCS(zwykle liczba rdzeni procesora).
Działanie:
- Harmonogram (część runtime Go) umieszcza nowe goroutine w globalnych lub lokalnych kolejach P.
- M, powiązany z P, pobiera goroutine z kolejki P i ją wykonuje.
- Gdy goroutine się blokuje (np. oczekując na I/O lub na mutexie):
- M odłącza się od aktualnego P.
- Harmonogram próbuje znaleźć inny M, aby zajął to P, lub tworzy nowy.
- Zablokowana goroutine jest umieszczana w specjalnej kolejce.
- Gdy blokada zostaje zdjęta, goroutine wraca do stanu runnable i trafia z powrotem do kolejki P.
- Gdy goroutine wyczerpuje swój kwant czasu lub jawnie oddaje kontrolę (rzadko), harmonogram może przełączyć M na inną goroutine w tym samym P.
Zalety:
- Efektywne wykorzystanie wątków systemowych M.
- Zmniejszenie kosztów przełączania kontekstu w porównaniu do natywnych wątków systemu operacyjnego.
- Równoważenie obciążenia między P za pomocą mechanizmu "work stealing" (M może ukraść goroutine z kolejki innego P).
Przykład tworzenia goroutine:
// main.go
package main
import (
"fmt"
"time"
)
func worker(id int) {
fmt.Printf("Pracownik %d zaczyna\n", id)
time.Sleep(time.Second) // Ilustracja blokady/zajętości
fmt.Printf("Pracownik %d kończy\n", id)
}
func main() {
for i := 1; i <= 5; i++ {
go worker(i) // Tworzymy nową goroutine
}
time.Sleep(time.Second * 2) // Czekamy na zakończenie goroutine
}