Используете ли вы воркерпул для ограничения количества горутин в Go
Что проверяют
Понимаете ли вы, что ограничивают не горутины, а нагрузку на то, что за ними: базу, внешний API, память, файловые дескрипторы. Горутина дешёвая, стартовый стек у неё в несколько килобайт, и сотня тысяч горутин сама по себе не проблема. Следом спрашивают, как вы выбрали число воркеров и что происходит при ошибке или отмене.
Как отвечать
Вопрос про ваш опыт, поэтому начните со случая: что обрабатывали, сколько задач, во что упирались, что сломалось без лимита. Затем назовите варианты:
- классический пул: N горутин читают задачи из канала
jobsи пишут вresults, отправитель закрываетjobs, послеwg.Wait()закрываетсяresults. Удобен, когда воркер держит состояние, например соединение; - семафор на буферизованном канале:
sem := make(chan struct{}, n), перед запуском горутиныsem <- struct{}{}, в конце<-sem. Горутина на задачу, но одновременно работают не больше n; errgroupсSetLimit(n)изgolang.org/x/sync/errgroup: лимит, первая ошибка и отмена контекста черезerrgroup.WithContext. Чаще всего это лучший вариант;semaphore.Weighted: когда задачи разного веса, например по памяти;rate.Limiterизgolang.org/x/time/rate: если внешний API ограничен запросами в секунду, нужен лимит скорости, а не параллелизма.
Число воркеров выбирают по узкому месту: для CPU-задач около runtime.GOMAXPROCS(0), для запросов в базу не больше SetMaxOpenConns пула соединений, для внешнего API по его лимиту. Проверяют нагрузочным тестом. Каждый воркер слушает ctx.Done(), иначе после отмены запроса горутины работают впустую.
Где спотыкаются
Ловят deadlock: основная горутина отправляет все задачи, ждёт wg.Wait() и только потом читает results. Воркеры блокируются на записи результата, и всё встаёт. Чтение результатов выносят в отдельную горутину.
Вызывают wg.Add(1) внутри запускаемой горутины. Wait может вернуться раньше, чем вырос счётчик; Add делают до go, а начиная с Go 1.25 есть метод WaitGroup.Go, который делает это сам.
Ставят пул везде по привычке. Если задач десяток и они короткие, хватит errgroup без лимита, а лишний пул только усложняет код.