Understanding and handling the Go routines is little bit tricky but once you got to know the cream of Go Routine it will be a cake walk of creating and handling the routines 👍
Updated the code with explanation
please go thru it and please feel free to add comments if i miss anything / you want to add something..!!
package main
import (
"fmt"
"sync"
"time"
)
const maxRoutines = 5
func main() {
HandleUsingWaitGroup()
HandleUsingChannel()
}
func HandleUsingWaitGroup() {
var wg sync.WaitGroup
// add no of go routines to trigger
wg.Add(maxRoutines)
for i := 1; i <= maxRoutines; i++ {
go waitGroupRoutine(&wg, i)
}
// it will block the main until all go routines run successfully
// whenever wg.Done() informs wait group it will reduce the go routine count by 1
// and it will block until it becomes zero(0)
wg.Wait()
}
func waitGroupRoutine(wg *sync.WaitGroup, value int) {
// this will inform wait group once it is done with the task
defer wg.Done()
fmt.Println("i am from waitGroup routine ", value)
}
// this works with buffered and unbuffered channels
func HandleUsingChannel() {
ch := make(chan int, maxRoutines+1)
//uncomment below line if you want to test un-buffered channel
//ch := make(chan int)
// this channel acts as a gatekeeper for the main func
exitCh := make(chan bool)
// this channel acts as a mediator to inform gatekeeper to exit main once all tasks are done
mediatorCh:=make(chan bool)
// trigger go routine and wait for the data in background
go channelRoutine(exitCh,mediatorCh, ch)
for i := 1; i <= maxRoutines; i++ {
// push data to channel
ch <- i
if i == maxRoutines {
// tell mediator to inform exit channel to exit the main func
// and it return the go routine / exit the go routine
mediatorCh <- true
// close the channel here and read residual data in routine
// else we will get a dead lock error because data push to channel is done
// and nothing to read from it and we are trying to access the same...
close(ch)
}
}
// it will block the main until all go routines run successfully
select {
case <-exitCh:
close(exitCh)
fmt.Println("exit from Channel main")
break
}
}
func channelRoutine(exitCh chan bool,mediatorCh chan bool, ch <-chan int) {
for {
select {
case <-mediatorCh:
// we can read from closed channel
close(mediatorCh)
// read residual data before exiting
// if we use buffered channel size of our data length
//it will have enough space to push data to channel
// once it pushes everything it will exit and routine will close automatically
//and to avoid data miss we have to read channel data before returning
for v := range ch {
// this will show the difference in logs while comparing buffered and un-buffered channels
time.Sleep(time.Second * 1)
fmt.Println(" i am from channel routine exit state", v)
}
// here we are telling exit channel to exit the main
exitCh<-true
return
case x := <-ch:
fmt.Println(" i am from channel routine", x)
}
}
}
please follow medium for interesting things
Top comments (0)