Middle+
Erzählen Sie uns vom Muster der Gleichzeitigkeitverwaltung (GMP) in der Programmiersprache Go.
sobes.tech KI
Antwort von AI
GMP ist ein Planungsmodell für die Ausführung von Goroutines in Go, bei dem:
- G (Goroutine): Leichtgewichtiger Ausführungs-Thread, eine Abstraktion über System-Threads.
- M (Machine): Ein Thread des Betriebssystems. Kann den Code einer oder mehrerer Goroutines ausführen.
- P (Processor): Ein logischer Prozessor, der einen Kontext für die Ausführung von Goroutines repräsentiert. Jedem P ist ein M zugewiesen, und P enthält eine lokale Warteschlange für runnable Goroutines. Die Anzahl der P ist standardmäßig
$GOMAXPROCS(normalerweise die Anzahl der Prozessorkerne).
Funktionsweise:
- Der Scheduler (Teil des Go-Runtime) platziert neue Goroutines in die globalen oder lokalen Warteschlangen von P.
- Ein M, das mit einem P verbunden ist, nimmt eine Goroutine aus der Warteschlange von P und führt sie aus.
- Wenn eine Goroutine blockiert (z.B. bei I/O oder einem Mutex):
- Das M löst sich vom aktuellen P.
- Der Scheduler versucht, ein anderes M zu finden, um dieses P zu übernehmen, oder erstellt ein neues.
- Die blockierte Goroutine wird in eine spezielle Warteschlange gestellt.
- Wenn die Blockierung aufgehoben wird, wird die Goroutine wieder runnable und kehrt in die Warteschlange von P zurück.
- Wenn die Goroutine ihr Zeitquantum verbraucht oder explizit die Kontrolle abgibt (selten), kann der Scheduler das M auf eine andere Goroutine im selben P umschalten.
Vorteile:
- Effiziente Nutzung der System-Threads M.
- Reduzierung der Kosten für Kontextwechsel im Vergleich zu nativen System-Threads.
- Lastenausgleich zwischen P durch den "work stealing"-Mechanismus (M kann eine Goroutine aus der Warteschlange eines anderen P stehlen).
Beispiel für die Erstellung einer Goroutine:
// main.go
package main
import (
"fmt"
"time"
)
func worker(id int) {
fmt.Printf("Worker %d startet\n", id)
time.Sleep(time.Second) // Illustration von Blockierung/Belegung
fmt.Printf("Worker %d beendet\n", id)
}
func main() {
for i := 1; i <= 5; i++ {
go worker(i) // Erstellen einer neuen Goroutine
}
time.Sleep(time.Second * 2) // Warten auf das Ende der Goroutines
}