DEV Community

sai teja
sai teja

Posted on • Updated on

Handle go routines gracefully

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)


        }
    }
}

Enter fullscreen mode Exit fullscreen mode

please follow medium for interesting things

Sai Teja – Medium

Read writing from Sai Teja on Medium. Software Engineer | Fitness trainer | Random Thinker. Every day, Sai Teja and thousands of other voices read, write, and share important stories on Medium.

favicon medium.com

Top comments (0)