package main import ( "fmt" "math/rand" "sync" "time" ) // Job represents a unit of work. type Job struct { ID int Payload string } // Result holds the outcome of a job. type Result struct { JobID int Output string Error error } // worker function 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 (Payload: %s) ", id, job.ID, job.Payload) // Simulate some work, e.g., an expensive computation or API call time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond) // Simulate success or failure if job.ID%3 == 0 { results <- Result{JobID: job.ID, Output: fmt.Sprintf("Job %d completed successfully", job.ID)} } else { results <- Result{JobID: job.ID, Error: fmt.Errorf("Error processing job %d", job.ID)} } } } func main() { rand.Seed(time.Now().UnixNano()) const numJobs = 15 const numWorkers = 3 // Create channels for jobs and results. jobs := make(chan Job, numJobs) results := make(chan Result, numJobs) var wg sync.WaitGroup // Start worker goroutines. for w := 1; w <= numWorkers; w++ { wg.Add(1) go func(workerID int) { defer wg.Done() worker(workerID, jobs, results) }(w) } // Send jobs to the jobs channel. for j := 1; j <= numJobs; j++ { jobs <- Job{ID: j, Payload: fmt.Sprintf("Data for Job %d", j)} } close(jobs) // Close the jobs channel to signal workers that no more jobs will be sent. // Wait for all workers to finish. wg.Wait() close(results) // Close the results channel after all workers are done. // Collect and print results. fmt.Println(" --- Results ---") for r := range results { if r.Error != nil { fmt.Printf("Job %d: ERROR - %v ", r.JobID, r.Error) } else { fmt.Printf("Job %d: %s ", r.JobID, r.Output) } } }