Sobes.tech
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:

  1. Der Scheduler (Teil des Go-Runtime) platziert neue Goroutines in die globalen oder lokalen Warteschlangen von P.
  2. Ein M, das mit einem P verbunden ist, nimmt eine Goroutine aus der Warteschlange von P und führt sie aus.
  3. 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.
  4. 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
}