Повторение — Worker Pool
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 66 из 107.
Задание
ЛегкоДавайте создадим систему обработки задач, используя паттерн "пул воркеров" (worker pool)! Вы создадите пул воркеров, которые одновременно обрабатывают вычислительные задачи, демонстрируя, как каналы, горутины и WaitGroups работают вместе для эффективной обработки рабочих нагрузок.
Вы организуете свой код в двух файлах:
pool.go: Определите компоненты и логику вашего пула воркеров.Создайте структуру
Taskс полямиID(int) иValue(int), представляющими работу, которую необходимо выполнить.Создайте структуру
Resultс полямиTaskID(int) иComputed(int), представляющими завершенную работу.Реализуйте функцию
Worker, которая принимает ID воркера (int), канал задач только для чтения (<-chan Task), канал для результатов только для записи (chan<- Result) и указатель наsync.WaitGroup. Каждый воркер должен:- Использовать
defer wg.Done()для сигнализации о завершении - Итерироваться (range) по каналу задач для обработки каждой задачи
- Для каждой задачи вычислить квадрат значения
Value - Отправить
ResultсTaskIDи вычисленным квадратом
Реализуйте функцию
RunPool, которая принимает количество воркеров (int) и срез задач. Эта функция должна:- Создать буферизованные каналы для задач и результатов (используйте количество задач в качестве размера буфера)
- Запустить указанное количество воркеров в виде горутин
- Отправить все задачи в канал задач, а затем закрыть его
- Использовать горутину с WaitGroup, чтобы закрыть канал результатов после того, как все воркеры закончат работу
- Собрать все результаты в срез и вернуть его
- Использовать
main.go: Чтение входных данных и координация пула воркеров.Прочитайте количество воркеров, затем количество задач. Для каждой задачи прочитайте её ID и значение. Вызовите
RunPoolс воркерами и задачами, затем выведите каждый результат в формате:Task [TaskID]: [Computed]Выведите результаты, отсортированные по TaskID в порядке возрастания.
Будут предоставлены следующие входные данные:
- Строка 1: Количество воркеров (целое число)
- Строка 2: Количество задач (целое число)
- Следующие строки: Для каждой задачи две строки — ID задачи (целое число), затем её значение (целое число)
Например, при вводе:
2
4
1
3
2
5
3
2
4
7Ваш вывод должен быть:
Task 1: 9
Task 2: 25
Task 3: 4
Task 4: 49Воркеры обрабатывают задачи параллельно (3 в квадрате — 9, 5 в квадрате — 25 и т. д.), а результаты собираются и отображаются по порядку ID задач. С 2 воркерами, обрабатывающими 4 задачи, работа эффективно распределяется по пулу.
Попробуйте сами
package main
import (
"fmt"
"sort"
)
func main() {
// Считать количество рабочих
var numWorkers int
fmt.Scanln(&numWorkers)
// Считать количество задач
var numTasks int
fmt.Scanln(&numTasks)
// Считать задачи
tasks := make([]Task, numTasks)
for i := 0; i < numTasks; i++ {
var id, value int
fmt.Scanln(&id)
fmt.Scanln(&value)
tasks[i] = Task{ID: id, Value: value}
}
// TODO: Вызвать RunPool с рабочими и задачами
// TODO: Отсортировать результаты по TaskID в порядке возрастания
// TODO: Вывести каждый результат в формате: Task [TaskID]: [Computed]
}
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП в Go
Внешние файлыРабочее пространство и модули GoПакеты и импортыЭкспортируемые и неэкспортируемые именаВведение в ООП в GoСтруктуры как классыОпределение методов структурПолучатели-указатели и получатели-значенияИнициализация структурФункции-конструкторыИтоги — Простой калькулятор4Интерфейсы
Введение в интерфейсыНеявная реализацияИнтерфейс как контрактПустой интерфейс (any)Утверждение типаПереключатель типовКомпозиция интерфейсовИнтерфейсы Stringer и ErrorПовторение: Калькулятор фигур7Инкапсуляция
Экспортируемые и неэкспортируемые поляИнкапсуляция на уровне пакетовГеттеры и сеттерыСокрытие информации в GoИтоги — Записи о студентах10Обобщения (Generics) (Go 1.18+)
Введение в GenericsПараметры типовОграничения типовОбобщенные структурыОбходной путь для обобщенных методовИтоги — Обобщенная коллекция13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн Abstract FactoryПаттерн ObserverПаттерн Strategy2Глубокое погружение в типы и структуры
Базовые и составные типыОпределение пользовательских типовТеги структурАнонимные структурыВложенные структурыНулевые значения и значения по умолчаниюПовторение — Контактная книга5Композиция вместо наследования
Почему в Go нет наследованияОсновы встраивания структурПродвижение методовВстраивание нескольких структурВстраивание против агрегацииЗатенение встроенных методовИтоги — Иерархия сотрудников8Обработка ошибок и ООП
Интерфейс errorПользовательские типы ошибокОбертывание ошибок (fmt.Errorf)Sentinel-ошибкиerrors.Is() и errors.As()Panic, Defer и RecoverИтоги — Парсер файлов11Стандартная библиотека и ООП
io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикMiddleware как Декоратор3Указатели и память
Основы указателей в GoУказатели на структурыПередача по значению и по ссылкеФункция new()Сборка мусора в GoПовторение: Конструктор связного списка6Полиморфизм в Go
Полиморфизм через интерфейсыУтиная типизация в GoПравила реализации интерфейсовПолиморфные коллекцииВнедрение зависимостейИтоги — Обработчик платежей9Конкурентность и ООП
Основы горутинКаналы и взаимодействиеБуферизованные и небуферизованные каналыОператор selectsync.Mutex и sync.RWMutexsync.WaitGroupПроектирование потокобезопасных структурПовторение — Worker Pool