Table of contents

Go: introduction to goroutines and concurrency

Go: introduction to goroutines and concurrency

As I mentioned in the introduction to the go programming language: go is a specialized concurrency language . It is a language that was designed to handle multiple tasks asynchronously. This entry is about go channels.

Concurrency is not parallelism

Before we begin, remember that parallelism and concurrency are different. This post is too small to deal with such a broad topic, however there are two resources I want to highlight:

I quote a sentence from the first resource that, in my opinion, sums up the difference quite well:

A program is concurrent if it can support two or more actions **in progress.

A program is parallel if it can support two or more actions executing simultaneously.

Felipe Restrepo Calle

If they still seem confusing and you don’t understand the difference, give those posts a read and you should be ready to move on.

Coroutines in go

A coroutine , in go, is a function or method that runs concurrently with other functions or methods. In go, corroutines are referred to as goroutines or goroutines. Even the main function, main, is executed inside one.

Goroutines are used in design patterns, such as the worker-pool-design-pattern

To generate a goroutine we add the keyword go before a function. This will schedule the function for asynchronous execution.

func write(texto string) {
fmt.Println(texto)
}
fmt.Println("hey")
go write("hey again")
// hey

In the above case, due to its asynchronous nature, the goroutine does not stop code execution. This implies that the body of the main function continues its execution and **our goroutine never executes.

Goroutine operation in go

But then, how do we get our goroutine to run? The naive approach would be to use a sleep to pause the execution of the code. This, as you know, is nonsense, we can’t be putting sleeps everywhere, the flow of the program would be unnecessarily slowed down!

// Don't
time.Sleep(1 * time.Second)

A better approach would be to create a WaitGroup.

WaitGroups in go

A WaitGroup will stop the execution of the program and wait for the goroutines to be executed.

Internally, a WaitGroup works with a counter, when the counter is at zero the execution of the code will continue, while if the counter is greater than zero, it will wait for the other goroutines to finish executing.

var wg sync.WaitGroup

wg.Wait()
fmt.Println("If waitgroup counter is greater than 0 it will continue the execution.")

And how do we change the counter value?

To increment and decrement the counter of the WaitGroup we will use the Add and Done methods, respectively.

The Add method

The Add method increments the WaitGroup counter by n units, where n is the argument we pass to it.

The trick is to call it every time you run a goroutine.

wg.Add(1)
go write("Hey")

The Done Method

The Done method is responsible for decrementing one unit of the WaitGroup counter. We will call it to tell the WaitGroup that the goroutine has finished and decrement the counter by one.

func write(text string, wg *sync.WaitGroup) {
    fmt.Println(text)
    wg.Done()
}

Remember that the instance of the WaitGroup (wg *) needs to be passed by reference or else we will not access the original WaitGroup.

func write(text string, wg *sync.WaitGroup) {
    fmt.Println(text)
    defer wg.Done()
}

Tip: use defer over the Done method to ensure that it is the last thing to be executed.

Operation of a waiting group in go

Once the wg.wait counter becomes zero, program execution continues.

var wg sync.WaitGroup
wg.Add(1)
go writeInChannel("Hello", &wg)
wg.Wait()

Anonymous functions in goroutines

When using goroutines, it is quite common to use anonymous functions to avoid declaring a new function.

go func() {
}()

Remember that the parentheses that appear after the body of the function execute the anonymous function that we declare and also receive its arguments.

go func(text string) {
}("Text")

More resources about goroutines

Finally, here are some other resources on goroutines that you can consult.

Eduardo Zepeda
Web developer and GNU/Linux enthusiast. I believe in choosing the right tool for the job and that simplicity is the ultimate sophistication. Better done than perfect. I also believe in the goodnesses of cryptocurrencies outside of monetary speculation.
Read more