Какие есть варианты ограничения количества одновременно работающих горутин кроме семафоров?
Что проверяют
Понимаете ли вы разницу между ограничением одновременности, ограничением частоты и простым ожиданием завершения. Буферизованный канал как счётчик слотов это тоже семафор, поэтому интервьюер ждёт других моделей: пул воркеров, errgroup с лимитом, конвейер. Следом обычно спрашивают, как в выбранной схеме отменить работу и собрать ошибки.
Как отвечать
- пул воркеров: запускаете ровно N горутин, которые читают задачи из общего канала
jobsи пишут вresults. Когда задачи кончились,close(jobs), воркеры выходят изfor range,sync.WaitGroupдожидается всех, после чего закрываетсяresults. Число горутин фиксировано по построению, а не счётчиком; errgroupс лимитом: пакетgolang.org/x/sync/errgroup, методSetLimit(n). Вызовg.Goблокируется, пока заняты все n слотов, аTryGoне блокируется и возвращаетfalse.errgroup.WithContextотменяет контекст при первой ошибке,Waitеё возвращает;- конвейер с фиксированным fan-out: каждая стадия обслуживается заданным числом горутин, связанных каналами. Обратное давление даёт блокировка на канале;
- готовые пулы:
ants,pond,conc/poolсWithMaxGoroutines. Полезны, когда нужны переиспользование горутин, метрики или динамический размер; - деление входа на части: вместо горутины на элемент режете данные на N кусков, по горутине на кусок.
Отдельно оговорите, что golang.org/x/time/rate ограничивает частоту операций, а не число одновременно выполняемых задач, а GOMAXPROCS ограничивает число потоков, параллельно исполняющих Go-код, но не количество горутин.
Где спотыкаются
Называют context или sync.Mutex способом ограничения. Контекст отменяет работу, мьютекс защищает данные, и ни один из них не ограничивает число горутин.
Закрывают канал results из воркера или забывают закрыть jobs. Итог: паника при записи в закрытый канал или вечное ожидание в range.
Запускают горутину на каждый элемент, а лимит ставят внутри неё. Горутины уже созданы, память под миллион стеков уже занята, ограничена только часть работы.