Middle
Jak správně ukončit běh několika gorutin v Go?
sobes.tech AI
Odpověď od AI
Existuje několik běžných způsobů:
-
Použití kontextu (Context): Doporučený přístup k zrušení operací ve stromové struktuře volání. Kontext může přenášet signál zrušení přes kanál.
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d končí: %v\n", id, ctx.Err()) return default: fmt.Printf("Goroutine %d pracuje...\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() // Odeslání signálu zrušení time.Sleep(1 * time.Second) // Dáváme čas gorutinám na ukončení fmt.Println("Hlavní program byl ukončen.") } -
Použití kanálů: Odesláním signálu (například prázdné struktury
struct{}) přes speciální kanál lze oznámit gorutině nutnost ukončení.package main import ( "fmt" "time" ) func worker(stopChan <-chan struct{}, id int) { for { select { case <-stopChan: fmt.Printf("Goroutine %d končí přes kanál\n", id) return default: fmt.Printf("Goroutine %d pracuje...\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) // Zavření kanálu signalizuje ukončení time.Sleep(1 * time.Second) // Dáváme čas gorutinám na ukončení fmt.Println("Hlavní program byl ukončen.") } -
Použití
sync.WaitGroup(pro čekání, nikoliv pro signalizaci):WaitGroupse používá k čekání na dokončení skupiny gorutin, ale sám o sobě neposkytuje mechanismus zastavení. Často se používá ve spojení s kontextem nebo kanály.package main import ( "context" "fmt" "sync" "time" ) func worker(ctx context.Context, wg *sync.WaitGroup, id int) { defer wg.Done() // Snižuje čítač WaitGroup při dokončení gorutiny for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d končí\n", id) return default: fmt.Printf("Goroutine %d pracuje...\n", id) time.Sleep(1 * time.Second) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup numWorkers := 2 wg.Add(numWorkers) // Inicializace WaitGroup for i := 1; i <= numWorkers; i++ { go worker(ctx, &wg, i) } time.Sleep(3 * time.Second) cancel() // Signál zrušení wg.Wait() // Čekání na dokončení všech gorutin fmt.Println("Hlavní program byl ukončen.") }
Volba metody závisí na konkrétním případě použití a složitosti interakcí gorutin. Obecně je kontext preferován pro kaskádové zrušení.