package main import ( "fmt" "math/rand" "sync" "time" ) // Job represents a task to be processed type Job struct { ID int Payload string } // Result holds the outcome of a processed job type Result struct { JobID int Output string Err error } // worker processes jobs from the jobs channel and sends results to the results channel func worker(id int, jobs <-chan Job, results chan<- Result) { for job := range jobs { fmt.Printf("Worker %d processing job %d: %s ", id, job.ID, job.Payload) // Simulate some work, e.g., an API call or computation time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond) res := Result{ JobID: job.ID, Output: fmt.Sprintf("Job %d processed by worker %d", job.ID, id), Err: nil, // In a real app, handle potential errors } results <- res fmt.Printf("Worker %d finished job %d ", id, job.ID) } } func main() { const numJobs = 15 const numWorkers = 3 jobs := make(chan Job, numJobs) results := make(chan Result, numJobs) var wg sync.WaitGroup // Start workers for w := 1; w <= numWorkers; w++ { wg.Add(1) go func(workerID int) { defer wg.Done() worker(workerID, jobs, results) }(w) } // Send jobs for j := 1; j <= numJobs; j++ { jobs <- Job{ID: j, Payload: fmt.Sprintf("Data-%d", j)} } close(jobs) // Close the jobs channel after all jobs are sent // Wait for all workers to finish processing jobs wg.Wait() // Close results channel once all workers are done (and thus no more results will be sent) close(results) // Collect and print results fmt.Println(" --- Results ---") for r := range results { if r.Err != nil { fmt.Printf("Error processing job %d: %v ", r.JobID, r.Err) } else { fmt.Printf("Received: %s ", r.Output) } } fmt.Println("All jobs processed and results collected.") }