Как избежать потери ошибок при параллельном выполнении горутин в Go
Что проверяют
Понимаете ли вы, что горутина не возвращает значение и ошибка из неё по умолчанию просто исчезает. Интервьюер ждёт, что вы назовёте готовые инструменты, а не только каналы из учебника. Следом обычно спрашивают, как остановить остальные горутины после первой ошибки.
Как отвечать
Начните с причины: go f() отбрасывает результат функции, поэтому ошибку нужно явно доставить туда, где её ждут. Дальше способы по возрастанию удобства:
- буферизованный канал: ёмкость равна числу горутин, закрытие после
wg.Wait()в отдельной горутине, чтение черезrange; - слайс ошибок по индексу:
errs := make([]error, len(tasks)), каждая горутина пишет только в свойerrs[i], послеwg.Wait()ошибки склеиваются черезerrors.Join(есть с Go 1.20). Мьютекс не нужен, гонки нет; errgroup.Groupизgolang.org/x/sync/errgroup:g.Go(func() error {...})запускает задачу,g.Wait()дожидается всех и возвращает первую ненулевую ошибку. Это стандарт де-факто;errgroup.WithContext: при первой ошибке отменяет общийctx, остальные задачи должны сами проверятьctx.Done()и выходить.g.SetLimit(n)ограничивает число одновременных горутин.
Скажите, что «первая ошибка» и «все ошибки» это разные требования: errgroup отдаёт одну, а для отчёта по всем задачам нужен слайс или канал. С Go 1.25 у sync.WaitGroup есть метод Go, который сам делает Add и Done, но ошибки он тоже не собирает. И отдельно про панику: она в ошибку не превращается, а recover в вызывающей горутине чужую панику не поймает, его ставят через defer внутри самой горутины. Код с общими данными гоняйте с go test -race.
Где спотыкаются
Пишут в общую переменную var err error из нескольких горутин. Это гонка данных: какая ошибка останется, решает планировщик, а детектор гонок покажет проблему сразу.
Читают из небуферизованного канала только первую ошибку и выходят. Остальные горутины навсегда блокируются на отправке, получается утечка.
Используют WithContext, но не передают ctx в запросы и циклы внутри задач. Контекст отменён, а горутины работают до конца, и отмена ничего не даёт.