Koks požiūris naudojamas klaidoms, kurios atsiranda Go goručinuose, apdoroti?
sobes.tech AI
Atsakymas iš AI
Go kalbant apie klaidų apdorojimą gorutinėse, dažniausiai naudojami šie požiūriai:
-
Klaidų perdavimas per kanalus: Sukuriamas kanalas klaidų perdavimui pagrindiniam srautui arba kitai gorutinai, kuri gali jas apdoroti:
// Klaidos perdavimo pavyzdys per kanalą func worker(id int, errors chan<- error) { // ... darbo vykdymas if somethingWentWrong { errors <- fmt.Errorf("klaida gorutinoje %d", id) return } // ... sėkmingas užbaigimas } func main() { errorCh := make(chan error, nWorkers) // Būseninis kanalas for i := 0; i < nWorkers; i++ { go worker(i, errorCh) } for i := 0; i < nWorkers; i++ { err := <-errorCh if err != nil { log.Printf("aptikta klaida: %v", err) // Klaidos apdorojimas } } } -
Naudojant
sync.WaitGroupir klaidų kanalą:sync.WaitGrouppadeda laukti visų gorutinų pabaigos, o kanalas naudojamas klaidų surinkimui:// Pavyzdys su WaitGroup ir klaidų kanalu func workerWithWG(id int, wg *sync.WaitGroup, errors chan<- error) { defer wg.Done() // ... darbo vykdymas if somethingWentWrong { errors <- fmt.Errorf("klaida gorutinoje %d", id) } } func main() { var wg sync.WaitGroup errorCh := make(chan error, nWorkers) for i := 0; i < nWorkers; i++ { wg.Add(1) go workerWithWG(i, &wg, errorCh) } wg.Wait() close(errorCh) // Svarbu uždaryti kanalą po WaitGroup for err := range errorCh { log.Printf("aptikta klaida: %v", err) // Klaidos apdorojimas } } -
Grąžinant reikšmę ir klaidą iš funkcijos, vykdomos gorutinėje: Jei gorutina atlieka konkretų darbą ir gali grąžinti rezultatą ir/ar klaidą, ją galima apgaubti funkcija, kuri grąžina šias reikšmes:
// Pavyzdys, grąžinantis reikšmę ir klaidą type result struct { value int err error } func doSomething(id int) (int, error) { // ... darbo vykdymas if somethingWentWrong { return 0, fmt.Errorf("klaida gorutinoje %d", id) } return id * 10, nil } func main() { results := make(chan result, nWorkers) for i := 0; i < nWorkers; i++ { go func(idx int) { val, err := doSomething(idx) results <- result{val, err} }(i) } for i := 0; i < nWorkers; i++ { res := <-results if res.err != nil { log.Printf("aptikta klaida: %v", res.err) // Klaidos apdorojimas } else { log.Printf("rezultatas: %d", res.value) } } } -
Konteksto (
context.Context) naudojimas atšaukimo ir klaidų apdorojimo: Kontekstas gali būti naudojamas signalizacijai apie gorutinų atšaukimą arba klaidos perdavimui žemyn hierarchijoje:// Pavyzdys su kontekstu func workerWithContext(ctx context.Context, id int, errors chan<- error) { select { case <-ctx.Done(): errors <- fmt.Errorf("gorutina %d atšaukta: %v", id, ctx.Err()) return default: // ... darbo vykdymas if somethingWentWrong { errors <- fmt.Errorf("klaida gorutinoje %d", id) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) errorCh := make(chan error, nWorkers) for i := 0; i < nWorkers; i++ { go workerWithContext(ctx, i, errorCh) } // Tam tikru momentu galima iškviesti cancel() atšaukimui // cancel() // Klaidų surinkimas go func() { for err := range errorCh { log.Printf("aptikta klaida: %v", err) } }() // Laukti pabaigos arba kitą logiką // ... }
Pasirinkimas priklauso nuo konkrečių reikalavimų klaidų apdorojimui ir programos architektūros.