Introduction to Concurrency in Go: Gopher FarmOlena StoliarovaBlockedUnblockFollowFollowingApr 11Concurrency can be very tricky for beginners.
Reading articles about gophers loading ore and looking at animations that represent goroutines is what helped me a lot when I started learning Go.
However, there is a gap between these beginner-friendly articles and real-world projects where you often cannot use familiar analogs.
I totally agree that practice is the best way to learn things and after you read some theory you should try new things out yourself.
That is why I adore programming kata.
Today I want to describe a step-by-step solution to a very funny one I had to solve during a job interview.
The task is as follows: you receive a JSON string that represents a farm where gophers live (sleep and eat actually) and the amount of food in units (perhaps grams as gophers are small animals) these gophers have in the barn.
As no more food grows on the farm, our gophers will die one by one when they have nothing to eat.
If this is too sad for you, feel free to code Chapter 2 where food trucks come to the farm and gohpers breed.
First, we need to turn inputJson into a structure we will use later.
Each element in the “gophers” array has the same structure.
Let’s turn it into a type Gopher.
It’s up to you how to name fields but it’s better to name them after JSON fields for better code readability.
JSON tags after field declarations are optional but I strongly recommend to have them in case you have a different order of fields of the same type in the structs you are going to unmarshal.
Check that struct fields are public or exported (e.
start with a capital letter) because standard Unmarshal function from json package cannot change values of private fields (visibility limitation).
Type Farm represents the whole inputJson.
We will put type declarations outside of the main function to access them from other functions.
Unmarshal accepts a byte and a struct we want to fill with values.
So let’s initialize a variable gopherFarm of type Farm and convert inputJson to byte.
It is a very good practice to log errors because they help to debug if something goes wrong.
There are many custom Go loggers used in real-world applications but for this small kata, log package is enough.
Gophers come to the farm and will live there independently of each other.
It means that we need separate goroutines for each gopher and (obviously) gophers should be able to live (gopherLive function).
Let’s populate the farm and write a boilerplate for a gopher lifecycle.
What does a gopher do?.It sleeps, then it wakes up, eats and sleeps again, and so on.
We need to keep track of all our gophers from their arrival to their death.
There is a great package sync that can take care of all the goroutines.
We will create an instance of sync.
WaitGroup and when adding a new gopher increase the number of goroutines we follow by one.
We will need this instance in gopherLive function to signal that at some point a gopher is no longer alive and we are done here.
Defer is a Go way to tell that the function must be executed before the end of the surrounding function.
It will be executed even if this function panics.
The last and the most challenging task is to make farm food available to gophers.
Here are the new eatFood function and updated gopherLive function.
We can run this code (add time.
Second*20)) at the end of the main function to see log output.
Probably, everything will be fine… or won’t.
the problem with this code is that it may happen that two or more gophers (goroutines) attempt to read and change the amount of food on the farm at the same time.
This condition is called a data race.
To check for a data race, simply run the application with -race flag:$ go run -race main.
goYou will see the similar output:Here comes another feature from sync package: Mutex, mutual exclusion lock.
It will prevent simultaneous read/write operations for Farm from multiple gophers.
We will add a private field mu of type sync.
Mutex to the Farm type and lock it when a gopher looks if there is some food left:We are almost done!.A final touch is to add more information about gopher life.
You can find the full code in my GitHub repository or run on Go Playground.
I hope that it was helpful and interesting.
Be creative and keep practicing!.