So currently the WaitGroup
is not being used to wait for the producing to complete. This means that it is possible for this programme to run without producing any results as each go produce()
is done in it's own go routine so true
can be sent immediately to dummy
if the main go routine gets all the CPU time thus main exits with nothing being printed.
Personally I would use the WaitGroup to do the waiting and then close
the msgs
channel to indicate to the consume
that it is done and use a further WaitGroup to then indicate to main that consume is done.
In addition to the concurrency parts, I also wouldn't use global variables but instead pass them into the functions that use them. Putting this together then you get:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func main() {
msgs := make(chan int)
// Start the consuming go routine before producing so that we can then just wait for the producing
// to complete on the main go routine rather than having to have a separate go routine to wait to
// close the channel.
var consumeWG sync.WaitGroup
consumeWG.Add(1)
go consume(msgs, &consumeWG)
var produceWG sync.WaitGroup
numberOfProducers := 10
for i := 0; i < numberOfProducers; i++ {
produceWG.Add(1)
go produce(msgs, &produceWG) // Multiple producers
}
// Wait for producing to complete then tell the consumer by closing the channel.
produceWG.Wait()
close(msgs)
consumeWG.Wait()
}
func produce(msgs chan int, wg *sync.WaitGroup) {
defer wg.Done()
msgs <- getRandomIntegerNumber()
}
// Single consumer
func consume(msgs chan int, wg *sync.WaitGroup) {
// Range of msgs, this will consume all messages in the channel then exit when the channel is closed.
// This provides communication between the go routines when completion has happened as well as not
// leaking the consuming go routine as would happen with an forever loop.
for msg := range msgs {
if msg%2 != 0 {
fmt.Printf(" The number %d is odd \n", msg)
}
}
wg.Done()
}
func getRandomIntegerNumber() int {
rand.Seed(time.Now().UnixNano())
return rand.Intn(1000)
}