errgroup для конкурентной обработки ошибок
Использование golang.org/x/sync/errgroup на практике
«errgroup для конкурентной обработки ошибок» — бесплатный урок Go Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Go Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Go Academy содержит 4 уроков всего.
Проблема горутин и ошибок
Запуск горутин с помощью go func() отбрасывает возвращаемые значения, включая ошибки. Для их сбора нужны дополнительные средства (каналы, WaitGroup). errgroup упрощает эту задачу.
golang.org/x/sync/errgroup
errgroup.Group запускает горутины и собирает ошибки. Wait() блокируется до завершения всех горутин и возвращает первую ошибку, отличную от nil.
var g errgroup.Group
g.Go(func() error { return fetchUsers() })
g.Go(func() error { return fetchOrders() })
if err := g.Wait(); err != nil {
log.Fatal(err)
}errgroup.WithContext
WithContext возвращает группу и производный контекст. Контекст отменяется, когда первая горутина возвращает ошибку, что останавливает оставшуюся работу.
g, ctx := errgroup.WithContext(context.Background())
g.Go(func() error { return doWork(ctx) })
g.Go(func() error { return doOtherWork(ctx) })
err := g.Wait()Сбор результатов вместе с ошибками
errgroup собирает только ошибки, но не результаты. Сохраняйте результаты в заранее выделенных срезах, обращаясь к ним по индексу, чтобы избежать синхронизации:
results := make([]Result, len(items))
for i, item := range items {
i, item := i, item
g.Go(func() error {
r, err := process(ctx, item)
if err != nil { return err }
results[i] = r
return nil
})
}
if err := g.Wait(); err != nil { return err }g.SetLimit (Go 1.20+)
g.SetLimit(n) ограничивает количество горутин, выполняющихся одновременно, — это встроенный семафор без отдельного канала.
g.SetLimit(10) // at most 10 goroutines at once
for _, item := range items {
g.Go(func() error { return process(item) })
}g.TryGo
g.TryGo(f) запускает горутину, только если ограничение (заданное через SetLimit) это позволяет. Если горутина не запущена, возвращается false.
Возвращается только первая ошибка
errgroup возвращает только первую ошибку. Если нужны все ошибки, собирайте их в защищённый мьютексом срез внутри каждой горутины.
var mu sync.Mutex
var errs []error
g.Go(func() error {
if err := doWork(); err != nil {
mu.Lock(); errs = append(errs, err); mu.Unlock()
}
return nil
})Отличие от sync.WaitGroup
WaitGroup отслеживает завершение, а errgroup отслеживает завершение и собирает ошибки. Предпочитайте errgroup, если о сбое любой горутины нужно сообщить.
Передача отмены контекста
При использовании errgroup.WithContext отмена производного контекста сигнализирует всем остальным горутинам остановиться — это аналогично семантике отмены при первой ошибке.
Тестирование кода с errgroup
В тестах внедряйте контекст с WithTimeout, чтобы группа не выполнялась бесконечно, если горутина зависнет.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
g, ctx := errgroup.WithContext(ctx)Альтернатива семафору
До появления SetLimit (Go < 1.20) используйте буферизованный канал как семафор внутри отдельных горутин, чтобы добиться того же эффекта.
Быстрая проверка
Что возвращает errgroup.WithContext в отличие от обычного errgroup.Group?
Повторение: errgroup
Основные моменты:
- g.Go(func() error) — запуск и сбор первой ошибки
- g.Wait() — блокируется до завершения всех горутин; возвращает первую ошибку
- WithContext — контекст отменяется при первой ошибке
- g.SetLimit(n) — ограничивает количество одновременно работающих горутин (Go 1.20+)
Часто задаваемые вопросы
Урок «errgroup для конкурентной обработки ошибок» бесплатный?
Да — полный текст урока «errgroup для конкурентной обработки ошибок» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Go Academy, подпишись на CoddyKit PRO. Курс Go Academy содержит 4 уроков всего.
Чему я научусь в уроке «errgroup для конкурентной обработки ошибок»?
Использование golang.org/x/sync/errgroup на практике Ты практикуешь Go Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Go Academy?
Предыдущий опыт не требуется. Go Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «errgroup для конкурентной обработки ошибок»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Go Academy?
Да. Каждый урок Go Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Шаблоны конвейеров и этапов
- errgroup для конкурентной обработки ошибок
- Шаблон семафора
- Обнаружение утечек и отмена