Hoe beëindig je correct de uitvoering van meerdere goroutines in Go?
sobes.tech AI
Antwoord van AI
Er zijn verschillende gangbare methoden:
-
Gebruik van de context (Context): Aanbevolen aanpak voor het annuleren van operaties in een boomstructuur van oproepen. De context kan een annuleringssignaal via een kanaal doorgeven.
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d wordt beëindigd: %v\n", id, ctx.Err()) return default: fmt.Printf("Goroutine %d werkt...\n", id) time.Sleep(1 * time.Second) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) go worker(ctx, 1) go worker(ctx, 2) time.Sleep(3 * time.Second) cancel() // Verstuur het annuleringssignaal time.Sleep(1 * time.Second) // Wacht tot de goroutines beëindigd zijn fmt.Println("Hoofdschema beëindigd.") } -
Gebruik van kanalen: Door een signaal (bijvoorbeeld een lege structuur
struct{}) via een speciaal kanaal te sturen, kan een goroutine geïnformeerd worden dat deze moet stoppen.package main import ( "fmt" "time" ) func worker(stopChan <-chan struct{}, id int) { for { select { case <-stopChan: fmt.Printf("Goroutine %d wordt beëindigd via kanaal\n", id) return default: fmt.Printf("Goroutine %d werkt...\n", id) time.Sleep(1 * time.Second) } } } func main() { stopChan := make(chan struct{}) go worker(stopChan, 1) go worker(stopChan, 2) time.Sleep(3 * time.Second) close(stopChan) // Het sluiten van het kanaal signaleert beëindiging time.Sleep(1 * time.Second) // Wacht tot de goroutines beëindigd zijn fmt.Println("Hoofdschema beëindigd.") } -
Gebruik van
sync.WaitGroup(om te wachten tot het eind, niet om te signaleren):WaitGroupwordt gebruikt om te wachten tot een groep goroutines klaar is, maar biedt geen mechanisme om te stoppen. Het wordt vaak gecombineerd met contexten of kanalen.package main import ( "context" "fmt" "sync" "time"
)
func worker(ctx context.Context, wg *sync.WaitGroup, id int) {
defer wg.Done() // Verlaagt de teller van de WaitGroup bij voltooiing
for {
select {
case <-ctx.Done():
fmt.Printf("Goroutine %d wordt beëindigd\n", id)
return
default:
fmt.Printf("Goroutine %d werkt...\n", id)
time.Sleep(1 * time.Second)
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
numWorkers := 2
wg.Add(numWorkers) // Initialiseer de WaitGroup
for i := 1; i <= numWorkers; i++ {
go worker(ctx, &wg, i)
}
time.Sleep(3 * time.Second)
cancel() // Signaal om te annuleren
wg.Wait() // Wacht tot alle goroutines klaar zijn
fmt.Println("Hoofdschema beëindigd.")
}
```
De keuze van de methode hangt af van de specifieke use case en de complexiteit van de interacties tussen goroutines. Context wordt over het algemeen geprefereerd voor cascade-onderbrekingen.