Golang Concurrency Part II

In Part I, we just converted a sequential program to a multithreaded one and did it with a very simple example. But real world problems are more complex then that. Now assume a server which confirms your login via OTP SMS and same is done for 10000 users per second. Now that’s what I called a problem.

Solution: As a simple design I will create independent jobs, one will handle the login part and other will handle the OTP SMS part. So, SMS job will just run independently of the login job. That’s how SMS job can be reused for other user logins. Now there is a need that both jobs must communicate.

Golang has provided a mechanism known as Channels. I this part of blog I will explain basics of channels.

Channels

In simple words, Channels are the connection between goroutines. Let’s discuss some facts and then a straight forward example will make it clear.

  • Each golang channel has a data type,  like int, string or struct {}. E.g. ca chan int. ca is channel variable and chan int is how we can declare channel.
  • We need to use make() to actually create a channel. e.g. ch := make(chan int). If, we don’t make a channel it cannot be used and will cause panic.
  • We can pass channels as function arguments and they are automatically passed a s reference.

Using A Channel

Channel has three operations defined.

  1. Read. (Eg. ch-<x) // write x to channel ch
  2. Write. (x := <-ch) // read channel into x
  3. Close. (We will discuss close in detail.)

Close

  • If we send on a channel after closing it, panic will occur.
  • If we read from a channel after closing it, first all the unread valued will be read and after that read will always read the zero value of channel.

Kinds of Channel

  1. Unbuffered.
  2. Buffered.

In this part we must stick to unbuffered channel and it’s complexities. In next blog we will take on buffered channel.

Unbuffered channels

Unbuffered channels are also called, Synchronous channels. Because they work in a manner that only one operation can be performed at a time, either Read or Write.

e.g.

ch := make(chan int) is a Unbuffered channel. There are few rules about them.

  1. If channel is not empty, send operation will block. Executing a receive will make channel available for send.
  2. If a channel is empty, receive operation will block. We have to perform send operation.

Example (Toggle Me)

package main

import (
       "fmt"
       "sync"
)
var wg sync.WaitGroup

func toggle(ch <-chan int) {


       for k := range ch { // reads from channel until it's closed
              fmt.Println("================================>" , k*k)
       }

       // this will be called only if we close the channel.. :-)
       wg.Done()

}



func main() {
       // create a channels
       ch1 := make(chan int)
       ch2 := make(chan int)
       ch3 := make(chan int)


       // launch go routines

       wg.Add(3)
       defer wg.Wait()


       go toggle(ch2)
       go toggle(ch3)


       go toggle(ch1)


       for i:=2;i<10;i++ {
              //writing data to channels
              ch1<-i
              ch2<-i
              ch3<-i

              fmt.Println(i)
       }

       //close the channels we need range toggle to return
       close(ch1)
       close(ch2)
       close(ch3)
}

Note: If we are using the wait-group with channels, just remember that every goroutine being waited is exited. So, if you have used range on channels, do close them so that range loop exit.

In the coming sections we will discuss some, concurrency patterns and buffered channels. Till then happy coding.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s