Go Concurrency: goroutines

Anurag Patel
Geek Farmer
Published in
7 min readOct 17, 2019

When Go was launched many people were saying that Go is a parallel language but it is concurrent language. Concurrency is the most prominent feature of Go. Go not only supports concurrency but also make it better. If you are confused between Concurrency and Parallelism you can understand quickly from my previous article.

Concurrency is about dealing with lots of things at once and Parallelism is about doing lots of things at once.

Finally, we reached a point where we can discuss how concurrency is implemented in Go. Goroutines and channels implement concurrency in Go. In this article, we are going to discuss how goroutines implement concurrency in Go and after that, we will discuss how we can use goroutine in a Go program.

you should know what is goroutine before going through how it works.

What is goroutine?

Goroutine is simply a function or method. When we use goroutine in our program, it runs concurrently in the background with other goroutines. Go provides go keyword (use as a prefix) for defining any function or method goroutine.

when we run a non-goroutine function, we have to wait for it till it executes. But when we use goroutine function, we don’t have to wait for it until its execution because it's running in the background independently without interrupting other goroutine and no-goroutine functions. We can better understand with below Go program:

In the above program, hello and world are non-goroutine function. When control transfer to hello function, then world function will wait for it till it executes.

Let's define hello function as a goroutine.

In the above program, when control transfer to hello goroutine, it runs in the background and world function didn’t wait for it till it executes. We can see this in the output, world function print ‘world’ without waiting for hello function. Now you are thinking that why ‘hello’ not print in output after ‘world’. That’s also a very interesting story, we will discuss it later.

A goroutine is a function or method, that is running concurrently in the background in the same address space with other goroutines without interrupting them

All Go program has one goroutine by default which is the main goroutine. every other goroutine works under the main goroutine. If your main goroutine terminated, all other goroutines in the program will also terminate. You can consider the main goroutine as an anonymous goroutine.

How goroutine works in Go?

Goroutine is a function executed in a thread that is dedicated to a chunk of stack space and managed by go runtime, it’s not dependent on hardware. Goroutines are stored in the stack and the size of the stack can grow and shrink according to the requirement of the program. But in threads, the size of the stack is fixed. A goroutine is created initially with 2KB of stack size. Go runtime checks for each goroutine that they needed more stack or not and stack an copied to other regions of memory with twice the original size. This makes goroutine as a lightweight thread.

Goroutine is an activity (it can be a function or method) that is concurrently executing. Even every concurrently executing activity inside Go runtime is a goroutine. The cost of creating a goroutine is cheaper than thread, it's not free but it’s cheap.

Goroutines are multiplexed onto multiple OS threads. That’s why when a goroutine blocked (suppose for I/O operation), it blocks that thread but not other goroutines, go runtime start a new OS thread to handle the other goroutines until blocked goroutine unblocked. Here go runtime works as a scheduler for goroutines.

Goroutines can communicate using the channel and these channels are specially designed to prevent race conditions when accessing shared memory using Goroutines. We will discuss channels in the next article.

Use goroutine in Go Program

When you create a hello world! program in Go, you don’t know but you are using goroutine by default.

When you run a go program, there is an unknown goroutine which calls main function, we call this goroutine main goroutine. That's how you already using goroutine.

In the above program, we created a normal hello function and when we run the above program, we will get the desired result as below:

Main goroutine started
Hello world
Main goroutine stopped

Let's create a goroutine function.

New goroutine can be created using the go keyword. In the above program, go hello() syntax starts a new goroutine, which will run concurrently with the main goroutine.

When you will run the above program, you will get the output:

Main goroutine started
Main goroutine stopped

Now you are thinking that what happened to our hello goroutine output, for that you have to understand three main properties of goroutine:

  • Go never block the program execution, when a new Goroutine is started because it runs in the background. the goroutine call returns immediately. Unlike functions, the control does not wait for the Goroutine to finish executing. The control returns immediately to the next line of code after the Goroutine call and any return values from the Goroutine are ignored.
  • The main Goroutine should be running for any other Goroutines to run. If the main Goroutine terminates then the program will be terminated and no other Goroutine will run.
  • We can’t pass the control to another goroutine until the current goroutine is scheduled.

In the above program, there are two goroutines are running concurrently main goroutine and hello goroutine. We have to modify the above program in such a way that control can transfer to hello goroutine before the main goroutine terminates the execution. We can make sleep main goroutine for some time and pass the control to hello goroutine.

In the above program, the main goroutine would not schedule for the next 5 milliseconds. After hello goroutine executes, control will transfer to the main goroutine and it will print the last line of code (after 5 milliseconds). Final output will be like below:

Main goroutine started 200ns
Hello goroutine 1.536081ms
Main goroutine stopped 6.015346ms

This is the hack for other goroutines to finish their execution, we use this for understanding how goroutines work. There is a concept called channels, which can be used to communicate between goroutines and also can be used to handle all goroutine’s executions. We will discuss channels in the next article.

Handle Multiple Goroutines

In Go, we can write as many as you want the number of goroutines. Let's write a program, in which we will start to goroutines(lets call them small-goroutine and caps-goroutine), one will print all characters in small and another will print all characters in caps.

In the above program, both goroutines will run concurrently. The main goroutine will start both goroutines and will take some sleep for 60 milliseconds. Then small-goroutine will sleep initially for 4 seconds and then print ‘h’, then sleeps again for 4 seconds and print next character ‘l’ and the same cycle happens till it prints last character ‘l’. The similar cycle will happen with caps-goroutine and we will get output like this ‘hElLoWoRlD’:

Main goroutine started h E l L o W o R l D Main goroutine stopped

The execution process of the above program will be more understandable with the below execution process diagram. In the Execution diagram, we can see the same pattern as we discussed above.

Don’t know how to stop goroutine, then don’t start it

Goroutines are cheap to create and efficient to schedule due to go runtime. Go runtime can handle tens of thousands of goroutine. But you can’t create an infinite number of goroutine because in terms of memory goroutine has finite cost.

If you are going to start a goroutine, you must know how and when your goroutine will exit otherwise your program will create a memory leak.

--

--