package main import ( "fmt" "sync" "time" ) // producer sends tasks to a channel. func producer(taskCount int, tasks chan<- int) { for i := 0; i < taskCount; i++ { tasks <- i + 1 fmt.Printf("Producer: Sent task %d ", i+1) } close(tasks) fmt.Println("Producer: All tasks sent.") } // worker processes tasks and sends results to a channel. func worker(id int, tasks <-chan int, results chan<- string, wg *sync.WaitGroup) { defer wg.Done() for task := range tasks { fmt.Printf("Worker %d: Processing task %d... ", id, task) time.Sleep(time.Duration(task%3+1) * 200 * time.Millisecond) // Simulate work result := fmt.Sprintf("Worker %d completed task %d", id, task) results <- result fmt.Printf("Worker %d: Finished task %d. ", id, task) } fmt.Printf("Worker %d: Shutting down. ", id) } // collector receives results from workers. func collector(results <-chan string, done chan<- struct{}) { for result := range results { fmt.Printf("Collector: Received result: %s ", result) } fmt.Println("Collector: All results collected.") done <- struct{}{} } func main() { const numTasks = 10 const numWorkers = 3 tasks := make(chan int) results := make(chan string) done := make(chan struct{}) // Signal for collector completion var wg sync.WaitGroup // Start the producer go producer(numTasks, tasks) // Start workers (Fan-Out) for i := 1; i <= numWorkers; i++ { wg.Add(1) go worker(i, tasks, results, &wg) } // Start the collector (Fan-In) go collector(results, done) // Wait for all workers to finish, then close the results channel go func() { wg.Wait() close(results) fmt.Println("Main: All workers done, closing results channel.") }() // Wait for the collector to finish processing all results <-done fmt.Println("Main: All tasks processed and collected. Exiting.") }