Middle
Kako pravilno završiti izvršavanje više gorutina u Go?
sobes.tech АИ
Одговор од АИ
Постоји неколико уобичајених начина:
-
Коришћење контекста (Context): Препоручени приступ за отказивање операција у дрвовитој структури позива. Контекст може преносити сигнал отказа преко канала.
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("Горутинa %d се завршава: %v\n", id, ctx.Err()) return default: fmt.Printf("Горутинa %d ради...\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() // Пошаљи сигнал отказа time.Sleep(1 * time.Second) // Дамо време горутинaма да се заврше fmt.Println("Главни програм је завршен.") } -
Користећи канале: Пошаљите сигнал (нпр. празну структуру
struct{}) преко специјалног канала, што може обавестити горутину о потреби за завршетком.package main import ( "fmt" "time" ) func worker(stopChan <-chan struct{}, id int) { for { select { case <-stopChan: fmt.Printf("Горутинa %d се завршава преко канала\n", id) return default: fmt.Printf("Горутинa %d ради...\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) // Затварање канала сигнализира завршетак time.Sleep(1 * time.Second) // Дамо време горутинaма да се заврше fmt.Println("Главни програм је завршен.") } -
Користећи
sync.WaitGroup(за чекање, а не за сигнализацију):WaitGroupсе користи за чекање да се група горутиних заврши, али сам по себи не пружа механизам за заустављање. Често се користи у комбинацији са контекстом или каналима.package main import ( "context" "fmt" "sync" "time" ) func worker(ctx context.Context, wg *sync.WaitGroup, id int) { defer wg.Done() // Смањује бројач `WaitGroup` када се заврши горуина for { select { case <-ctx.Done(): fmt.Printf("Горутинa %d се завршава\n", id) return default: fmt.Printf("Горутинa %d ради...\n", id) time.Sleep(1 * time.Second) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup numWorkers := 2 wg.Add(numWorkers) // Иницијализујемо `WaitGroup` for i := 1; i <= numWorkers; i++ { go worker(ctx, &wg, i) } time.Sleep(3 * time.Second) cancel() // Сигнал за отказивање wg.Wait() // Чекамо да се заврше све горутине fmt.Println("Главни програм је завршен.") }
Избор метода зависи од конкретног случаја употребе и сложености интеракција горутиних. Контекст је генерално пожељан за каскадне отказе.