0Pricing
Go Academy · Урок

Паттерн пула работников

Ограничивайте параллелизм

«Паттерн пула работников» — бесплатный урок Go Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Go Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Go Academy содержит 4 уроков всего.

Что такое пул worker

Пул worker запускает фиксированное число горутин, которые получают задания из общего канала. Вместо запуска одной горутины для каждой задачи Вы запускаете N worker и передаёте им работу.

  • Ограничивает число параллельных операций
  • Повторно использует горутины вместо создания тысяч новых
  • Защищает общие ресурсы, например базы данных или программные интерфейсы

Зачем ограничивать параллелизм

Неограниченное число горутин может исчерпать память и файловые дескрипторы или перегрузить зависимую службу. Пул даёт Вам возможность управлять объёмом работы, выполняемой одновременно.

Если Вам нужно получить данные с 10000 адресов, не следует отправлять 10000 одновременных HTTP-запросов. Пул из 20 worker сохраняет нагрузку на разумном уровне.

Канал задач

Задания поступают в канал jobs. Каждый worker читает из него в цикле for range. Когда канал закрывается, цикл завершается и worker выходит.

jobs := make(chan int, 100)
for j := 1; j <= 5; j++ {
    jobs <- j
}
close(jobs)

Один worker

worker — это всего лишь функция, перебирающая канал задач. Она обрабатывает каждую задачу и записывает результат в канал результатов.

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        results <- j * 2
    }
}

Запуск нескольких worker

Запустите пул простым циклом. На каждой итерации запускается одна горутина с той же функцией worker. Все они используют общие каналы задач и результатов.

for w := 1; w <= 3; w++ {
    go worker(w, jobs, results)
}

Направленные типы каналов

Обратите внимание на <-chan int (только для получения) и chan<- int (только для отправки) в сигнатуре worker. Эти направленные типы позволяют компилятору запретить worker случайно отправлять данные в канал задач или читать данные из канала результатов.

Сбор результатов

После передачи всех заданий и закрытия канала главная горутина читает ровно столько результатов, сколько было заданий. Это синхронизирует программу и не позволяет ей завершиться раньше времени.

sum := 0
for a := 1; a <= 5; a++ {
    sum += <-results
}
fmt.Println("total:", sum)

Полный рабочий пул

Вот полный шаблон в одной программе: три worker удваивают пять чисел. Запустите её и посмотрите на итог.

package main

import "fmt"

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        results <- j * 2
    }
}

func main() {
    jobs := make(chan int, 5)
    results := make(chan int, 5)
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }
    for j := 1; j <= 5; j++ {
        jobs <- j
    }
    close(jobs)
    total := 0
    for a := 1; a <= 5; a++ {
        total += <-results
    }
    fmt.Println("total:", total)
}

Буферизованный и небуферизованный канал

Буферизованный канал задач позволяет производителю ставить работу в очередь, не блокируясь, пока буфер не заполнится. Небуферизованный канал требует непосредственной передачи: отправка блокируется, пока worker не будет готов. Буферизация сглаживает резкие всплески работы производителя.

Выбор размера пула

Для работы, ограниченной возможностями CPU, задавайте размер пула близким к runtime.NumCPU(). Для работы, ограниченной IO (сетью или диском), размер можно сделать гораздо больше, поскольку worker тратят время на ожидание, а не на вычисления.

package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Println("CPUs:", runtime.NumCPU())
}

Предотвращение утечек горутин

Если забыть вызвать close(jobs), worker навсегда заблокируются на пустом канале, что приведёт к утечке. Всегда закрывайте канал задач после отправки всей работы, чтобы циклы for range завершались.

Быстрая проверка

Проверьте, насколько хорошо Вы понимаете пулы worker.

Итоги

Вы изучили шаблон пула worker:

  • Запускайте фиксированное количество worker, читающих из общего канала задач
  • Используйте направленные типы каналов для безопасности
  • Закрывайте канал задач, чтобы завершить worker
  • Собирайте результаты для синхронизации завершения
  • Выбирайте размер пула в зависимости от типа нагрузки (CPU или IO)

Часто задаваемые вопросы

Урок «Паттерн пула работников» бесплатный?

Да — полный текст урока «Паттерн пула работников» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Go Academy, подпишись на CoddyKit PRO. Курс Go Academy содержит 4 уроков всего.

Чему я научусь в уроке «Паттерн пула работников»?

Ограничивайте параллелизм Ты практикуешь Go Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Go Academy?

Предыдущий опыт не требуется. Go Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Паттерн пула работников»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Go Academy?

Да. Каждый урок Go Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Паттерн пула работников
  2. Fan-Out и Fan-In
  3. Этапы конвейера
  4. Корректное завершение
← Назад к Go Academy