← Назад к вопросам

Что такое error group?

2.3 Middle🔥 171 комментариев
#Конкурентность и горутины

Комментарии (1)

🐱
qwen3.5-flashPrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Error Group в экосистеме Go

В профессиональной среде разработки на языке Go, когда собеседующий спрашивает про error group, речь почти всегда идет о популярном пакете golang.org/x/sync/errgroup. Это не стандартная библиотека, но это де-факто индустриальный стандарт для безопасной координации работы множества горутин. Основная задача этого инструмента — объединить логику sync.WaitGroup с механизмом обработки возвращаемых ошибок.

Принципы работы и архитектура

Пакет errgroup предназначен для группировки выполнения функций, запущенных в отдельных горутинах. Ключевая особенность заключается в том, что он позволяет блоку кода приостановиться на выполнение метода Wait, пока все спавненные горутины не завершатся, и автоматически вернуть первую ошибку, возникшую в любом из потоков.

Это решает классическую проблему гон данных при сборе ошибок в глобальную переменную. Без помощи errgroup вам пришлось бы использовать atomic операции или мьютексы для записи ошибки, что усложняет код. Механизм работает следующим образом:

  • Go: Запускает метод в отдельной горутина.
  • Wait: Блокирует текущую горутику до завершения всех работ. Возвращает nil, если все успешно, или первую ошибку, если одна из них не была nil.
  • WithContext: Позволяет связать работу группы с конкретным context, обеспечивая прозрачную отмену операций.
package main

import (
	"context"
	"fmt"
	"golang.org/x/sync/errgroup"
	"time"
)

func process(ctx context.Context) error {
	select {
	case <-time.After(100 * time.Millisecond):
		fmt.Println("done")
	case <-ctx.Done():
		return ctx.Err()
	}
	return nil
}

func main() {
	// Создаем контекст и группу с отменой
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	g, ctx := errgroup.WithContext(ctx)

	// Запускаем горутины
	for i := 0; i < 5; i++ {
		i := i
		g.Go(func() error {
			return process(ctx)
		})
	}

	// Ждем завершения всех и ловим первую ошибку
	if err := g.Wait(); err != nil {
		fmt.Printf("Error occurred: %v\n", err)
	}
}

Важные нюансы и лучшие практики

При работе с errgroup важно помнить о нескольких критических правилах, которые выделит эксперт с опытом:

  • Принудительная отмена: Если одна горутина возвращает ошибку, это не гарантирует, что остальные сразу завершатся. Однако, при использовании WithContext, при возврате первой ошибки контекст часто отменяется.
  • Безопасность захвата переменных: В лямбда-функции внутри g.Go всегда создавайте локальную копию цикловой переменной, чтобы избежать ошибок переполнения стека или гонок при обращении к ней.
  • Не блокируйте Wait: Метод Wait должен вызываться только после того, как все работы добавлены, иначе программа завершится преждевременно.

Использование этого паттерна делает ваш код более читаемым, безопасным и устойчивым к параллельному исполнению задач в высоконагруженных системах.

Что такое error group? | PrepBro