package main import ( "fmt" "sync" "time" ) // simulateWork processes an ID and sends a result to a channel. func simulateWork(id int, resultChan chan<- string, wg *sync.WaitGroup) { defer wg.Done() fmt.Printf("Worker %d: Starting work... ", id) time.Sleep(time.Duration(id) * 500 * time.Millisecond) // Simulate varying work times result := fmt.Sprintf("Worker %d finished at %s", id, time.Now().Format(time.RFC3339)) resultChan <- result fmt.Printf("Worker %d: Finished work. ", id) } func main() { numWorkers := 3 resultChannel := make(chan string, numWorkers) // Buffered channel to avoid blocking workers var wg sync.WaitGroup fmt.Println("Launching workers...") for i := 1; i <= numWorkers; i++ { wg.Add(1) go simulateWork(i, resultChannel, &wg) } // Close the result channel once all workers are done go func() { wg.Wait() close(resultChannel) fmt.Println("All workers finished, closing result channel.") }() // Collect results from the channel fmt.Println("Collecting results...") for res := range resultChannel { fmt.Printf("Main: Received result: %s ", res) } fmt.Println("All results collected. Main routine exiting.") }