Skip to main content

Goroutines in Go

In this tutorial, we are going to discuss Goroutines, a unique feature of the Go programming language that enables easy and efficient handling of concurrent activities. Concurrency in Go is achieved using Goroutines and Channels. However, we will focus solely on Goroutines in this article.

What are Goroutines?

Goroutines can be defined as functions or methods that run concurrently with other functions or methods. They are lightweight threads, managed by Go runtime rather than the operating system. The advantage of Goroutines is that they allow us to perform multiple tasks at the same time, increasing the efficiency and performance of our program.

go function_name()

To create a Goroutine, we use the keyword go followed by a function call. The control does not wait for the Goroutine to finish, instead, it moves on to the next line, making Goroutines non-blocking.

Simple Goroutine Example

Let's start with a very basic example:

package main

import (
"fmt"
"time"
)

func hello() {
fmt.Println("Hello world goroutine")
}
func main() {
go hello()
time.Sleep(1 * time.Second)
fmt.Println("main function")
}

In the above program, we have two functions: hello and main. The main function starts a new Goroutine by using the go keyword followed by the hello function call. After that, it waits for 1 second and prints main function. The hello Goroutine prints Hello world goroutine.

How Goroutines Work?

Goroutines are multiplexed into small number of OS threads. When a new Goroutine is started, the Go runtime checks if there is a current OS thread available. If there is, it will use it; if not, it will create a new one.

One important feature of Goroutines is their size. A Goroutine has a small stack size which grows and shrinks according to the need. This makes Goroutines lightweight and more manageable than threads.

Synchronization using Channels

In our previous example, we used time.Sleep to wait for the Goroutine to finish before exiting the program. However, this is not an ideal solution. Go provides a better mechanism for synchronization, known as Channels. Channels allow Goroutines to communicate with each other and synchronize their execution.

Here is an example:

package main

import (
"fmt"
)

func hello(done chan bool) {
fmt.Println("Hello world goroutine")
done <- true
}
func main() {
done := make(chan bool)
go hello(done)
<-done
fmt.Println("main function")
}

In the above code, we create a channel done using the make function. We pass this channel to the hello Goroutine. Inside the hello Goroutine, after printing Hello world goroutine, we send a true signal to the done channel. In the main function, we receive from the done channel. This line of code is blocking, which means the main function will wait until it receives from the done channel to proceed any further.

Conclusion

Goroutines are one of the most powerful features of Go. They are lightweight, and easy to create and manage. They allow us to write concurrent programs with ease and improve the performance of our applications. To properly synchronize the execution of Goroutines, we use Channels. Remember that Goroutines are not threads, and they are managed by Go runtime, not the operating system. The understanding of Goroutines is essential to write efficient Go programs. Happy coding!