In this mini project, we'll write a pattern where worker goroutines pull jobs from a channel and process them. It's a good foundation for understanding real-world systems like background email senders, image processors, order processors, and queue workers.
go
package main
import (
"fmt"
"time"
)
func worker(id int, jobs <-chan string, results chan<- string) {
for job := range jobs {
fmt.Println("worker", id, "started", job)
time.Sleep(200 * time.Millisecond)
results <- fmt.Sprintf("worker %d finished %s", id, job)
}
}
func main() {
jobs := make(chan string, 3)
results := make(chan string, 3)
for w := 1; w <= 2; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= 3; j++ {
jobs <- fmt.Sprintf("job-%d", j)
}
close(jobs)
for r := 1; r <= 3; r++ {
fmt.Println(<-results)
}
}jobs channel gets filled with jobs, and worker goroutines pick them up using range jobs. The results channel sends the finished results back to the main function.
You should see
(Order may vary) worker 2 started job-1 worker 1 started job-2 worker 2 finished job-1 worker 1 finished job-2 worker 2 started job-3 worker 2 finished job-3Info
jobs <-chan string is a receive-only channel, and results chan<- string is a send-only channel. Specifying direction in the function signature makes your code safer.