> Как реализуется раздача заданий и синхронизация горутин в воркерпуле в Go (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Wildberries

Стек: Go

> Пример ответа

В Go раздача заданий и синхронизация горутин в воркерпуле обычно реализуется через комбинацию каналов и sync.WaitGroup. Основной подход: создается буферизированный канал для задач, фиксированное количество воркеров (горутин) читают из него, а синхронизация завершения работы обеспечивается через sync.WaitGroup.

Пример реализации:

GO
type WorkerPool struct {
tasks chan func()
wg sync.WaitGroup
quit chan struct{}
}
func NewWorkerPool(numWorkers int) *WorkerPool {
wp := &WorkerPool{
tasks: make(chan func(), 100), // буфер для задач
quit: make(chan struct{}),
}
for i := 0; i < numWorkers; i++ {
wp.wg.Add(1)
go wp.worker()
}
return wp
}
func (wp *WorkerPool) worker() {
defer wp.wg.Done()
for {
select {
case task, ok := <-wp.tasks:
if !ok {
return // канал закрыт - выходим
}
task() // выполняем задачу
case <-wp.quit:
return // сигнал остановки
}
}
}
func (wp *WorkerPool) Submit(task func()) {
wp.tasks <- task
}
func (wp *WorkerPool) Shutdown() {
close(wp.quit) // сигнал всем воркерам
close(wp.tasks) // закрываем канал задач
wp.wg.Wait() // ждем завершения всех воркеров
}

Ключевые моменты:

  • Канал tasks - буферизированный, чтобы не блокировать отправителя при временной занятости воркеров.
  • sync.WaitGroup - гарантирует, что Shutdown() дождется завершения всех горутин.
  • select в воркере позволяет реагировать как на новые задачи, так и на сигнал остановки.
  • Закрытие канала - идиоматичный способ остановки воркеров, но требует проверки ok при чтении.

Для более продвинутой синхронизации (например, с контекстом) можно использовать context.Context для graceful shutdown, а для динамического масштабирования - паттерн с sync.Pool или каналы с приоритетами.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью