Определите семантику жизненного цикла: ниже Start запускает пул один раз, Stop отменяет работу и ждёт работников. Задания поступают по внешнему каналу и обязаны поддерживать context.
Пул воркеров с управлением жизненным циклом
Определите семантику жизненного цикла: ниже Start запускает пул один раз, Stop отменяет работу и ждёт работников. Задания поступают по внешнему каналу и обязаны поддерживать context.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Требуется реализовать пул воркеров, который соответствует следующему интерфейсу:
type WorkerPool interface {
Start(ctx context.Context)
Stop()
}
Ответ
Определите семантику жизненного цикла: ниже Start запускает пул один раз, Stop отменяет работу и ждёт работников. Задания поступают по внешнему каналу и обязаны поддерживать context.
Реализация с context и sync:
type Pool struct {
mu sync.Mutex
wg sync.WaitGroup
jobs <-chan func(context.Context)
workers int
started, stopped bool
cancel context.CancelFunc
}
func NewPool(n int, jobs <-chan func(context.Context)) *Pool {
if n < 1 { panic("invalid worker count") }
return &Pool{workers: n, jobs: jobs}
}
func (p *Pool) Start(parent context.Context) {
p.mu.Lock()
defer p.mu.Unlock()
if p.started || p.stopped { return }
p.started = true
ctx, cancel := context.WithCancel(parent)
p.cancel = cancel
p.wg.Add(p.workers)
for i := 0; i < p.workers; i++ {
go func() {
defer p.wg.Done()
for {
if ctx.Err() != nil { return }
select {
case <-ctx.Done(): return
case job, ok := <-p.jobs:
if !ok { return }
if ctx.Err() != nil { return }
if job != nil { job(ctx) }
}
}
}()
}
}
func (p *Pool) Stop() {
p.mu.Lock()
p.stopped = true
cancel := p.cancel
p.mu.Unlock()
if cancel != nil { cancel() }
p.wg.Wait()
}
Повторные Start игнорируются; Stop до Start запрещает последующий запуск. Add выполняется под lock до возможности Stop.Wait, поэтому нет гонки регистрации работников. Stop не вызывают из самого задания: оно ожидало бы собственное завершение. Задание, игнорирующее отмену, способно задержать Stop; принудительного убийства горутины здесь нет.