Direkt zum Hauptinhalt springen
eLearner.app
Modul 7 · Lektion 4 von 534/50 im Kurs~14 min
Lektionen des Moduls (4/5)

`sync.Mutex` und `sync.WaitGroup`

Kanäle sind die Hauptsprache von Go, manchmal jedoch auch traditioneller Es werden Primitive benötigt. Das sync-Paket stellt Mutexe bereit, warten Sie Gruppen und andere Dienstprogramme zur Koordinierung des gemeinsamen Status.

sync.Mutex: exklusive Sperre

Go
import "sync"

type Counter struct {
    mu    sync.Mutex
    count int
}

func (c *Counter) Inc() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.count++
}

func (c *Counter) Get() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.count
}

Zwischen Lock() und Unlock() tritt jeweils nur eine Goroutine ein. Obligatorisches Muster: defer mu.Unlock() direkt nach Lock().

sync.RWMutex: viele Leser, ein Autor

Für den leseintensiven Zustand:

Go
var mu sync.RWMutex

mu.RLock()              // read lock: più goroutine simultanee OK
v := data
mu.RUnlock()

mu.Lock()               // write lock: esclusivo
data = newValue
mu.Unlock()

Nur nützlich, wenn die Lesevorgänge tatsächlich die Schreibvorgänge überwiegen; ansonsten ein Stammgast sync.Mutex ist dank geringerer interner Geschwindigkeit einfacher und oft schneller Streit.

sync.WaitGroup: Warte auf N Goroutinen

Go
var wg sync.WaitGroup

for i := 0; i < 3; i++ {
    wg.Add(1)
    go func(id int) {
        defer wg.Done()
        work(id)
    }(i)
}
wg.Wait()    // blocca finché tutti i Done() sono arrivati

Arbeitsablauf:

  1. wg.Add(N) erhöht den Zähler um N (bevor die Goroutinen gestartet werden).
  2. Jede Goroutine ruft wg.Done() auf, wenn sie fertig ist (idealerweise über defer).
  3. wg.Wait() blockiert, bis der Zähler wieder auf 0 geht.

sync.Once: Thread-sichere verzögerte Initialisierung

Go
var (
    once   sync.Once
    config *Config
)

func GetConfig() *Config {
    once.Do(func() {
        config = loadConfig()
    })
    return config
}

Der Rückruf in once.Do wird genau einmal ausgeführt, auch bei gleichzeitiger Ausführung Anrufe. Singleton/Lazy-Initialisierungsmuster.

Mutex vs. Kanal: Wann was verwenden

Richtlinien (auch aus der offiziellen Go-FAQ):

FallBevorzugtes Werkzeug
Übergabe des Eigentums an DatenKanal
Arbeit verteilen (Arbeitswarteschlange)Kanal
Koordinierung unabhängiger GoroutinenKanal
Ein Strukturfeld schützenMutex
Cache / ZählerMutex oder atomar
Singleton-Referenzsync.Once

„Zu orchestrierende Kanäle, Mutexe für gemeinsam genutzte Daten“ ist eine gute Faustregel.

Rassendetektor

Führen Sie Tests mit -race durch, um Datenrennen zu erkennen:

Bash
go test -race ./...
go run -race main.go

Der Race-Detektor instrumentiert die Binärdatei und protokolliert jede Unsynchronisation Zugriff auf den gemeinsamen Speicher. Es ist das Tool Nr. 1 zur Validierung von gleichzeitigem Code vor der Produktion.

Probieren Sie es aus

Übung#go.m7.l4.e1
Versuche: 0Wird geladen…

Schützen Sie die Erhöhung der Anzahl mit mu.Lock() + defer mu.Unlock().

Editor wird geladen…
Hinweis anzeigen

Das Aufschieben von mu.Unlock() direkt nach Lock() garantiert die Freigabe auch bei Panik.

Lösung nach 3 Versuchen verfügbar

Übung#go.m7.l4.e2
Versuche: 0Wird geladen…

Starten Sie 3 Goroutinen und warten Sie mit sync.WaitGroup (Add(3), Done() in jeder Goroutine, Wait()) auf alle.

Editor wird geladen…
Hinweis anzeigen

VOR dem Start der Goroutine hinzufügen; INNERHALB der Goroutine mit „Defer“ erledigt.

Lösung nach 3 Versuchen verfügbar

Quiz#go.m7.l4.e3
Bereit

Welches Muster wird empfohlen, um sicherzustellen, dass der Mutex freigegeben wird?

Go
mu.Lock()
// ?
Antwortoptionen

Zusammenfassung

  • sync.Mutex schützt den gemeinsamen Status; immer defer mu.Unlock().
  • Verwenden Sie einen Zeigerempfänger, um das Kopieren des Mutex zu vermeiden.
  • sync.RWMutex für Muster mit vielen Lesern/einem Schreiber (nur wenn es hilft).
  • sync.WaitGroup: Add vor go, Done mit defer, Wait zum Warten.
  • sync.Once: Thread-sichere verzögerte Initialisierung.
  • „Zu orchestrierende Kanäle, Mutexe für gemeinsam genutzte Daten“.
  • defer mu.Unlock()0: Tool Nr. 1 zum Erkennen von Datenrennen.