Ответ
errgroup
из пакета golang.org/x/sync/errgroup
— это мощный инструмент для управления группой горутин, которые выполняют связанные задачи. Он расширяет функциональность sync.WaitGroup
тремя ключевыми возможностями:
- Синхронизация и ожидание. Как и
WaitGroup
, он позволяет запустить несколько горутин и дождаться их завершения с помощью методаWait()
. - Обработка первой ошибки. Если любая из горутин в группе возвращает ненулевую ошибку,
Wait()
немедленно вернет эту ошибку. Это основной сценарий использования. - Отмена через контекст. При возникновении первой ошибки
errgroup
автоматически отменяетcontext
, связанный с группой. Это позволяет остальным горутинам грациозно завершить свою работу, прекратив бесполезные вычисления.
Ключевое отличие от sync.WaitGroup
:
WaitGroup
просто ждет завершения горутин, но не имеет встроенных механизмов для сбора ошибок или для отмены других горутин при сбое одной из них. errgroup
решает обе эти проблемы.
Пример использования:
// Создаем группу с контекстом, который будет отменен при первой ошибке.
g, ctx := errgroup.WithContext(context.Background())
urls := []string{
"http://example.com",
"http://example.net",
"http://invalid.url.that.will.fail",
}
for _, url := range urls {
// Запускаем каждую задачу в отдельной горутине.
// Важно передавать url в горутину как аргумент, чтобы избежать проблем с замыканием.
u := url
g.Go(func() error {
// http.Get автоматически учитывает отмену контекста.
resp, err := http.NewRequestWithContext(ctx, "GET", u, nil)
if err != nil {
return err // Возвращаем ошибку, что приведет к отмене контекста.
}
// ... какая-то работа с resp
fmt.Printf("Successfully fetched %sn", u)
return nil
})
}
// Ждем завершения всех горутин. Если была ошибка, она вернется здесь.
if err := g.Wait(); err != nil {
fmt.Printf("An error occurred: %vn", err)
}
Когда использовать: Идеально подходит для параллельного выполнения независимых задач (например, запросы к разным API, обработка файлов), где сбой одной задачи должен приводить к остановке всего процесса.