Tutorial : Go Concurrency - Goroutines, Channels with Examples (Part 1)

Tutorial : Go Concurrency - Goroutines, Channels with Examples (Part 1)
's picture

Hello Folks! Hope you are enjoying Golang Company blogs where we have already written about APi frameworks, data types and others.

Today, we will be covering one of the important concepts in Golang called Go Concurrency. This is where Go lang shines as it gives asynchronous ability to the language. Let’s start

First we will cover Goroutines.

What are Goroutines?

Goroutines is basically a function that is getting scheduled by go scheduler. Go has a scheduler which is created at the run time. Important thing is goroutines do not run in parallel, they run concurrently. It may be confusing so let me explain it more.

Parallelism vs concurrency

Here, l write a small program

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package main import ( "fmt" "time" ) func main() { fetchResource() fetchResource() fetchResource() fetchResource() fetchResource() fetchResource() fmt.Println("I am complete") } func fetchResource() string { time.Sleep(time.Second * 2) return "some string" }


If you see, we are creating a function fetchResource() and calling it multiple times. When we run this program it will take 12 seconds or more to complete and Print “I am complete” on the console. This is because every function has a wait time of 2 seconds.

But, if we prepend “go” then all function calls become concurrent and we will immediately get an “I am complete” message on the console.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package main import ( "fmt" "time" ) func main() { go fetchResource() //async call go fetchResource() go fetchResource() go fetchResource() go fetchResource() go fetchResource() go fetchResource() fmt.Println("I am complete") } func fetchResource() string { time.Sleep(time.Second * 2) return "some string" }

The above example can also be attained through anonymous function.

What is Anonymous function?

Let’s understand by example:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package main import ( "fmt" "time" ) func main() { go func() { ///anonymous function fetchResource() //async call fetchResource() fetchResource() fetchResource() fetchResource() fetchResource() fetchResource() }() fmt.Println("I am complete") } func fetchResource() string { time.Sleep(time.Second * 2) return "some string" }

Here we just created one anonymous function and every function inside that because goroutines functions. Here go is prepended to func() which is anonymous as it does not have any name.

One step deeper to Goroutine: Channels

In the above example we saw that func fetchResource is returning a string but we are not using it anywhere.
If we try to write something like below it will not work. This is because function calls are happening outside and concurrently at the run time.

1 2 3 4 5 6 7 8 9 10 func main() { go func() { ///anonymous function result:= fetchResource() fmt.Println(result) }() }

What are channels?

You can think of channels like a tunnel where we put one thing from one end and we receive the information on the other end. It is a way of communicating you may think of channels as a queue.

In General when we declare a channel we append “ch” to the variable so that others can understand that we are using channels.

How do we make channels?

We use make function/keyword to create a channel

Variable name := make(chan datatype)

We write into channel using <-

Let us understand with example:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package main import ( "fmt" ) func main() { resultch := make(chan string) resultch <- "golang company" // adding data to channel result := <-resultch // reading data from channel to variable fmt.Println(result) }

Comments are self explanatory. However when we run this program. We will get an ERROR!

I purposely did that so that when you will encounter later you understand the reason.


fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()

All goroutines are asleep why this happens. Now we have to understand the unbuffered and Buffered channels.

Unbuffered vs Buffered channels:

In the above example resultch := make(chan string) is unbuffered channel. And the channel in go lang will always block if it is full. Therefore we are getting the deadlock error as there is no buffer size mentioned and hence it was blocked.

Now how to declare buffered channel, resultch := make(chan string, 10). Here we have a buffered channel with size 10. Let's run the program again with a buffered channel.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import ( "fmt" ) func main() { resultch := make(chan string, 10) // buffered channel resultch <- "golang company" // adding data to channel result := <-resultch // reading data from channel to variable fmt.Println(result) }

It is running fine as the channel is not full. In our earlier code the moment we are adding string to our unbuffered channel it becomes full and therefore, getting deadlock error. So the channel should not be full as it will block.

So how we can make unbuffered channel work which is blocking us currently. Goroutine is the answer as it will schedule and will not block our channel. Let us understand with example:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package main import ( "fmt" ) func main() { resultch := make(chan string) // buffered channel go func() { resultch <- "golang company" // adding data to channel using go routine }() result := <-resultch // reading data from channel to variable fmt.Println(result) }

This will run without deadlock.


This is a complex thing in Golang. I tried to make it easier for you to understand with lots of code examples. I will dig deeper into channels in other parts. Keep reading. Have any issue or need to develop an application on Golang contact our golang developers.

So the above is more verbose to do. Range is cleaner but just showing you this can also be done.

Check the source code in the linked repository.

https://github.com/GolangCompany/go-concurrency-part01

Build Your Golang Team