Handle go routines gracefully
Tags: go, programming, tutorial, productivity
Published: 2022-11-24 09:55:16

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 {% embed https://medium.com/@tejasai651 %}