Recap - Worker Pool
Part of the Object Oriented Programming section of Coddy's GO journey — lesson 66 of 107.
Challenge
EasyLet's build a task processing system using the worker pool pattern! You'll create a pool of workers that concurrently process computational tasks, demonstrating how channels, goroutines, and WaitGroups work together to handle workloads efficiently.
You'll organize your code across two files:
pool.go: Define your worker pool components and logic.Create a
Taskstruct withID(int) andValue(int) fields representing work to be done.Create a
Resultstruct withTaskID(int) andComputed(int) fields representing completed work.Implement a
Workerfunction that takes a worker ID (int), a receive-only channel of tasks (<-chan Task), a send-only channel for results (chan<- Result), and a pointer to async.WaitGroup. Each worker should:- Use
defer wg.Done()to signal completion - Range over the tasks channel to process each task
- For each task, compute the square of the task's Value
- Send a Result with the TaskID and the computed square
Implement a
RunPoolfunction that takes the number of workers (int) and a slice of tasks. This function should:- Create buffered channels for tasks and results (use the number of tasks as the buffer size)
- Start the specified number of workers as goroutines
- Send all tasks to the tasks channel, then close it
- Use a goroutine with the WaitGroup to close the results channel after all workers finish
- Collect all results into a slice and return it
- Use
main.go: Read input and coordinate the worker pool.Read the number of workers, then the number of tasks. For each task, read its ID and value. Call
RunPoolwith the workers and tasks, then print each result in the format:Task [TaskID]: [Computed]Print results sorted by TaskID in ascending order.
The following inputs will be provided:
- Line 1: Number of workers (integer)
- Line 2: Number of tasks (integer)
- Following lines: For each task, two lines - the task ID (integer), then its value (integer)
For example, given:
2
4
1
3
2
5
3
2
4
7Your output should be:
Task 1: 9
Task 2: 25
Task 3: 4
Task 4: 49The workers process tasks concurrently (3 squared is 9, 5 squared is 25, etc.), and the results are collected and displayed in order by task ID. With 2 workers handling 4 tasks, the work is distributed across the pool efficiently.
Try it yourself
package main
import (
"fmt"
"sort"
)
func main() {
// Read number of workers
var numWorkers int
fmt.Scanln(&numWorkers)
// Read number of tasks
var numTasks int
fmt.Scanln(&numTasks)
// Read tasks
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: Call RunPool with workers and tasks
// TODO: Sort results by TaskID in ascending order
// TODO: Print each result in the format: Task [TaskID]: [Computed]
}
All lessons in Object Oriented Programming
1Fundamentals of Go OOP
External FilesGo Workspace & ModulesPackages & ImportsExported vs Unexported NamesIntroduction to OOP in GoStructs as ClassesDefining Methods on StructsPointer vs Value ReceiversStruct InitializationConstructor FunctionsRecap - Simple Calculator4Interfaces
Introduction to InterfacesImplicit ImplementationInterface as ContractEmpty Interface (any)Type AssertionType SwitchInterface CompositionStringer & Error InterfacesRecap - Shape Calculator7Encapsulation
Exported vs Unexported FieldsPackage-Level EncapsulationGetter & Setter MethodsInformation Hiding in GoRecap - Student Records10Generics (Go 1.18+)
Introduction to GenericsType ParametersType ConstraintsGeneric StructsGeneric Methods WorkaroundRecap - Generic Collection2Types & Structs Deep Dive
Basic & Composite TypesCustom Type DefinitionsStruct TagsAnonymous StructsNested StructsZero Values & DefaultsRecap - Contact Book5Composition Over Inheritance
Why Go Has No InheritanceStruct Embedding BasicsMethod PromotionEmbedding Multiple StructsEmbedding vs AggregationShadowing Embedded MethodsRecap - Employee Hierarchy8Error Handling & OOP
The error InterfaceCustom Error TypesError Wrapping (fmt.Errorf)Sentinel Errorserrors.Is() and errors.As()Panic, Defer, and RecoverRecap - File Parser3Pointers & Memory
Pointer Basics in GoPointers to StructsPass by Value vs ReferenceThe new() FunctionGarbage Collection in GoRecap - Linked List Builder6Polymorphism in Go
Polymorphism via InterfacesDuck Typing in GoInterface Satisfaction RulesPolymorphic CollectionsDependency InjectionRecap - Payment Processor9Concurrency & OOP
Goroutines BasicsChannels & CommunicationBuffered vs Unbuffered ChanSelect Statementsync.Mutex & sync.RWMutexsync.WaitGroupThread-Safe Struct DesignRecap - Worker Pool