Goroutines and Go Channels [Best examples]

Go concurrency plays an important role in go based application development.
Go supports Concurrency and not parallelism
If we have two tasks running on a multicore-processor, then each task is running independently or separately on each core and it is called parallelism. But for same two tasks if we have a single-core processor, then time-slice should be provided to each task to complete their execution and here it is called concurrency.
For Concurrency in Go we use Goroutines and channels.  They are very similar to threads as used in other languages and also run concurrently with other functions or methods. Let’s see how a Goroutine looks like.

A Goroutine Example

package main
import  “fmt”

func myhello() {
        fmt.Println(“My Hello World”)
}
func main() {
        go myhello()   //=====>  Starting a goroutine
        fmt.Println(“In main function”)
}

In main function

Here we have just seen how a goroutine looks like. But to make it work we have to modify it little bit. For now let’s understand some theory behind this.
Once you will run this program, you will get the output like:
In main function
Here, nothing will be print from myhello() Goroutine. The reason is when a new Goroutine starts, the main-Goroutine doesn’t wait for the new Goroutine to finish its execution. Hence here the myhello() Goroutine prints are ignored. Lets see how many ways we can fix this.
Lets fix this using time.sleep()

package main

import (
        “fmt”
        “time”
)

func myhello() {
        fmt.Println(“My Hello world”)
}
func main() {
        go myhello()
        time.Sleep(1 * time.Second)
        fmt.Println(“In main function”)
}

My Hello world
In main function

Now you can see the outputs like:
My Hello world
In main function

Here both the statements are printed. The reason is we have used a sleep of 1 sec or i,e waiting for new goroutine myhello() to complete its execution, before coming out of the main go routine.
This is just to understand how a Goroutine works, but its not a proper way to implement a Goroutine.
Lets see how we can fix it using channels:–

golang channel example

Concurrency is achieved in Go using Goroutines. Channels help to synchronize them. Using channels, the Goroutines communicate among them.

package main
import “fmt”

func myhello(ch chan bool) {
        fmt.Println(“My Hello world goroutine”)
        ch <- true //====>  Writing to the channel ch
}
func main() {
        ch1 := make(chan bool)
        go myhello(ch1)
        val := <-ch1 // ====> Reading from the channel ch1
        fmt.Println(“in main function, Returned value is “, val)
}

My Hello world goroutine
in main function, Returned value is  true

Here in main, we are waiting/reading from channel “ch1” and this waiting/reading will complete when someone will write something to this channel. So once the goroutine hello() complete its execution and write “true” to the channel then in the main it will able to read from the channel and executes further. Thus the output will be:–
My Hello world goroutine
in main function, returned value is  true

Thus instead of using time.sleep(), we can achieve it using channels and this is one of the best way to resolve it.

WaitGroup:—

Using Waitgroup, we can wait for multiple goroutines to finish their work. Thus the control is blocked until all Goroutines finish there execution

package main

import (
        “fmt”
        “sync”
)

func dataCollector1(wg *sync.WaitGroup) {
        fmt.Println(“In dataCollector1”)
        wg.Done()
}

func dataCollector2(wg *sync.WaitGroup) {
        fmt.Println(“In dataCollector2”)
        wg.Done()
}

func main() {
        wg := new(sync.WaitGroup)
        wg.Add(2)

        go dataCollector1(wg)
        go dataCollector2(wg)

        wg.Wait()
}

In dataCollector2
In dataCollector1

As above, we want the main gorouten should wait till both Goroutines are not complete. thus the output will be:–
Compared to go waitgroup, the go channel select  works differently. It is used to choose from multiple send/receive channel operations and it blocks until one of the send/receive operation is ready

Channel deadlock: —

You will get a deadlock, when you are trying to read from a channel, but none is writing to that channel. Its sometimes called as go channel timeout

package main

import “fmt”

func myhello(ch chan bool) {
        fmt.Println(“Hello World”)
        //ch <- true
}

func main() {
        ch1 := make(chan bool)
        go myhello(ch1)
        fmt.Println(“Value read from channel is “, <-ch1)
}

Hello World
fatal error: all goroutines are asleep – deadlock!

goroutine 1 [chan receive]:
main.main()
        /home/rjio/Go/src/MyGo/test.go:13 +0x79
exit status 2

As above you will get a deadlock, as you are trying to read from a channel “ch1”, where none is writing to it. i,e we have commented the line “ch <- true “, where we are trying to write into the same channel.

Leave a Reply

Your email address will not be published. Required fields are marked *