package main import ( "fmt" "math/rand" "time" ) // producer sends numbers to a channel func producer(id int, dataChan chan<- int) { defer fmt.Printf("Producer %d: Exiting ", id) for i := 0; i < 5; i++ { num := rand.Intn(100) fmt.Printf("Producer %d: Sending %d ", id, num) dataChan <- num // Send to the channel time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond) } } // consumer receives numbers from a channel and processes them func consumer(id int, dataChan <-chan int, done chan<- bool) { defer fmt.Printf("Consumer %d: Exiting ", id) for num := range dataChan { // Loop until the channel is closed fmt.Printf("Consumer %d: Received %d, processing... ", id, num) time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond) } done <- true // Signal that this consumer is done } func main() { rand.Seed(time.Now().UnixNano()) dataChan := make(chan int, 3) // Buffered channel to hold up to 3 items doneChan := make(chan bool) // Start producers go producer(1, dataChan) go producer(2, dataChan) // Start consumers numConsumers := 2 for i := 1; i <= numConsumers; i++ { go consumer(i, dataChan, doneChan) } // Wait for all producers to finish (not explicitly shown here, but dataChan will close) // A more robust solution would use a sync.WaitGroup for producers fmt.Println("Main: Producers and consumers started. Waiting for all items to be processed.") // Wait for all consumers to finish // This waits for the data channel to be closed and all items consumed go func() { // In a real scenario, you'd close the dataChan after all producers are done. // For this example, producers exit after 5 items, allowing the range loop to terminate. // This isn't perfect, but demonstrates the pattern. fmt.Println("Main: Simulating producers finishing and closing data channel...") time.Sleep(6 * time.Second) // Give producers enough time to send close(dataChan) // IMPORTANT: Close the channel to signal consumers no more data is coming }() for i := 0; i < numConsumers; i++ { <-doneChan // Wait for each consumer to signal completion } fmt.Println("Main: All producers finished, all items processed, all consumers exited.") }