Concurrency in Go ( Beginners )

Muhammad Haris
6 min readJun 26, 2022

Go is the strictly typed high level language that is developed by Google to make it easier to get the performance of C++ without writing any C++ code. The main highlight of the Go language is the concurrency which makes it a lot faster and more efficient for I/O operations and CPU-intensive tasks.

So the question is that what is concurrency and what's the difference between the concurrency and the parallel execution?

What is concurrency?

In simple words what concurrency means is that it divides the different tasks or processes and executes them in chunks by context switching and all that stuff is happening on a single thread.

What is parallelism?

In simple words what parallelism means is that it can run multiple tasks independently on different threads simultaneously without any interruption. In order to execute more parallel tasks, one needs the multicore CPU.

How does concurrency is working and achieved in Go language?

Go language hides a lot of low-level implementations to work with concurrency so people can focus only on the code-level implementations. In Go, the concurrent execution is called goroutines which is the main highlight of this language.

Let's dive into the code to see how goroutines work.

Note: I'm assuming that you know a little bit of Go language and it's already set up on your system.
Installation guide of Go.
Basics of Go language to get started.

Before the implementation of goroutines:

Before the implementation of goroutines
Before the implementation

Implementing goroutines

Implementing goroutines

So in this implementation, I push the printName("Haris") into the separate goroutine so that the main program can resume its execution without any interruption. So let's just observe the output of this program after implementing the goroutine.
PS. I used the time package of go so it can wait 1 second to print the next name.

As you can clearly see that now the program is executing concurrently without any problem and changing its context between the program execution. Cool right ? How go makes it easier to implement concurrent code.

Wait Groups:

What if I add both functions calls into the separate goroutines?

So it should work as expected, right? Let's find out and observe the output.

Output:

Strange! There is no output on the console so what's just happened here is both function executions are pushed in the separate goroutines and then the program control continues to execute the main function and when the main function complete it's execution it terminates and doesn't wait for the goroutines to complete their execution so what's the solution to this problem? Yes you guessed it right we can use wait groups to tell the main program that there is a goroutine that doesn't complete its execution so let's wait for the goroutine to complete before the main program gets terminated. Let's implement the wait groups.

Output:

So what's just happened here I imported the sync package from the go and create a wait group and then I added a goroutine counter in the wait group so you need to define the number of goroutines you need to wait for. I asked the main program to let's just wait for the wait group (goroutines to complete its execution). After defining the number of goroutines I execute the goroutine in an inline function and when the goroutine is done with the execution I decrement the goroutine counter which means at this point the wait group is 0 and there is no need to wait for further goroutines.

Channels

So the question is what if you need to share data between different goroutines which are executing independently? Don't worry go has a solution for this problem which is called channels. What you can do is you can create a channel to share data between goroutines and channels also help to synchronize the goroutines. Let's dive into the code and implements channels in go.

Output:

So what is happening in this code is I created a channel which accepts and pass string type of messages, go provide a built in function to create a channel and pass the reference of channel to the function and in the function defination I'm passing the message to the channel using the ← notation. The right hand side of the ← is the message and the left hand side is the channel which is accepting the message and after passing all the messages I need to close the channel so go doesn't throw any exception of unused channel. In the main function I used a loop to get all the messages from the channel. This mechenism is also helping to synchronize the goroutines because the channel is a blocking mechenism and blocks the execution of a goroutine until it receives the message from the channel.

Let's prove that channels blocks the execution until it receives the message from the channel.

Let's dive into the code and look at the example

So in this code I created a string type of channel and pass a message into the channel and then get the message from the channel and print the message that we get from the channel. So what's the expected output? any guesses ? Alright let's look into the output of this code.

So I didn't get the expected output so what's just happend here is I created a channel and pass a message to the channel but there is no receiver at that time of execution so the program execution gets blocked and throws the error of deadlock.

Let's discuss the solutions of this problem.

Goroutines

The first and a very simple solution to this problem is … yes you gussed it right goroutines. I need to pass the message to channel using the goroutine so it doesn't gets blocked and get the message from the channel in the main program execution let's see the implementation of deadlock problem using goroutines.

Output:

So by using the goroutines we solves the problem of deadlock.

Channel Buffers

The second solution of this problem can be solved by using the channel buffers. I need to define a sort of message count while creating the channel so it doesn't wait for the receiver and broadcast the message to the channel and doesn't block the execution of the program. Let's dive into the code.

Output:

Interesting right ? In this code I defined a channel buffer which means one message will be broadcast in the channel and one message will be received at one time.

I hope you guys learned a bit about concurrency in Go language.

So what I'm doing in this code is that I created a function that print the name infinitely which means "Haris" will be printed infinitely and "John" never gets printed on the console so what's the solution to this problem? Yes, you guessed it right it's goroutines so let's just implement the goroutine and observe the output of this program.

--

--