Eine häufige Anforderung bei der Arbeit mit Concurrency ist es,
sicherzustellen, dass mehrere Goroutines beendet sind, bevor das
Hauptprogramm fortfährt. Dafür verwendet Go das Paket sync
und speziell die WaitGroup.
Hier ein Beispiel, wie WaitGroup verwendet wird:
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
}In diesem Beispiel:
worker, die eine Nachricht
ausgibt, eine Sekunde schläft und dann eine andere Nachricht ausgibt.
Jede worker-Funktion nimmt eine
WaitGroup-Referenz als Parameter und ruft
wg.Done() auf, wenn sie fertig ist.main-Programm erstellen wir eine
WaitGroup-Instanz.worker-Funktion ausführen, und fügen jede von ihnen zur
WaitGroup hinzu, indem wir wg.Add(1)
aufrufen.wg.Wait() auf, um darauf zu
warten, dass alle Goroutines beendet sind, bevor das Programm
fortfährt.Ein weiteres wichtiges Konzept in der Concurrency ist der Schutz von
gemeinsam genutzten Ressourcen, um Datenrennen zu vermeiden. Dafür
verwendet Go das sync-Paket und den Mutex.
Hier ein Beispiel, wie Mutex verwendet wird:
package main
import (
"fmt"
"sync"
)
type Counter struct {
mu sync.Mutex
count int
}
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.count++
}
func (c *Counter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.count
}
func main() {
var wg sync.WaitGroup
counter := Counter{}
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 1000; j++ {
counter.Increment()
}
}()
}
wg.Wait()
fmt.Println("Final count:", counter.Value())
}In diesem Beispiel:
Counter-Struktur, die einen
Mutex und einen Zähler enthält.Increment-Methode sperrt den Mutex,
erhöht den Zähler und entsperrt den
Mutex wieder. Dasdefer-Schlüsselwort sorgt dafür, dass derMutex`
entsperrt wird, sobald die Methode beendet ist.Value-Methode sperrt den Mutex, gibt
den aktuellen Wert des Zählers zurück und entsperrt den
Mutex.main-Programm erstellen wir fünf Goroutines, die
jeweils tausend Mal die Increment-Methode aufrufen. Wir
verwenden eine WaitGroup, um sicherzustellen, dass alle
Goroutines abgeschlossen sind, bevor wir den endgültigen Zählerwert
ausgeben.