Пул воркеров с управлением жизненным циклом

Определите семантику жизненного цикла: ниже 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; принудительного убийства горутины здесь нет.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее