Goroutines

Goroutines

In this tutorial, we will discuss how concurrency is achieved in the Go language using Goroutines. Go language provides a special feature known as Goroutines.

A Goroutine is a function or method which executes independently and simultaneously in connection with any other Goroutines present in your program. Or in other words, every concurrently executing activity in the Go language is known as Goroutines.

A goroutine is a function that is capable of running concurrently with other functions. It is entirely managed by the GO runtime. Golang is a concurrent language. Each goroutine is an independent execution.

You can consider a Goroutine like a lightweight thread. The cost of creating Goroutines is minimal as compared to the thread.

Every program contains at least a single Goroutine, and that Goroutine is known as the main Goroutine.

Goroutine always works in the background. All the Goroutines are working under the main Goroutines. If the main Goroutine is terminated, then all the Goroutines present in the program are also terminated.

Goroutine vs Thread
Goroutines
How to start a Goroutine?

Golang uses the special keyword ‘go’ for starting a goroutine. To start one, just add the go keyword before a function or method call. That function or method will now be executed in the goroutine.

Note that it is not the function or method which determines if it is a goroutine. If we call that method or function with a go keyword then that function or method is said to be executing in a goroutine.

Let’s understand the difference between normal running a function and running a function as a goroutine.

Normal Running a function

statment1
start()
statement2

In the normal running of a function for the above scenario.

  1. First, statement1 will be executed
  2. Then start() function will be called
  3. Once the start() function finishes, then statement2 will be executed

Running a function as a goroutine

statment1
go start()
statement2

In running a function as a goroutine for the above scenario

  1. First, statement1 will be executed
  2. Then function start() will be called as a goroutine which will execute asynchronously.
  3. statement2 will be executed immediately. It will not wait for start() function to complete. The start function will be executed concurrently as a goroutine while the rest of the program continues its execution.

So basically, when calling a function as a goroutine, the call will return immediately. The execution will continue from the next line while the goroutine will be executed concurrently in the background. Also, note that any return value from the goroutine will be ignored.

Syntax

func name(){ 
   // statements 
}

// using go keyword as the prefix of your function call 
go name()
package main

import (
    "fmt"
)

func hello() {
    fmt.Println("Hello world")
}

func main() {
    go hello()
    fmt.Println("Hello this is the main function")
}

Output

Hello this is the main function

Run in playground

In the above program, go hello() starts a new Goroutine. Now the hello() function will run concurrently along with the main() function. The main function runs in its own Goroutine, and it’s called the main Goroutine.

Run this program and you will have a surprise..!!

This program only outputs the text Hello this is the main function. What happened to the Goroutine we started? We need to understand the two main properties of goroutines to know why this happens.

When a new Goroutine is started, 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. I guess now you will be able to understand why our Goroutine did not run.

After the call to go hello() in the above program, the control returned immediately to the next line of code without waiting for the hello goroutine to finish and printed the main function.

Then the main Goroutine terminated since there is no other code to execute, and hence the hello Goroutine did not get a chance to run. Let us fix this now.

using sleep
package main

import (
    "fmt"
    "time"
)

func hello() {
    fmt.Println("Hello world")
}

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

Output

Hello world 
Hello this is main function

Run in playground

In the above program, we have called the Sleep method of the time package, which sleeps the goroutine in which it is being executed.

In this case, the main Goroutine is put to sleep for 1 second. Now the call to go hello() has enough time to execute before the main Goroutine terminates.

This program first prints Hello world, waits for 1 second and then prints Hello this is the main function.

Using sleep in the main Goroutine to wait for other Goroutines to finish their execution is a hack we are using to understand how Goroutines work.

We can use channels to block the main Goroutine until all other Goroutines finish their execution. We will discuss channels in the following tutorial.

package main

import (
    "fmt"
    "time"
)

func display(str string) {
    for w := 0; w < 6; w++ {
        time.Sleep(1 * time.Second)
        fmt.Println(str)
    }
}

func main() {
    go display("Welcome")
    display("Waytoeasylearn")
}

Output

Welcome 
Waytoeasylearn 
Waytoeasylearn 
Welcome 
Welcome 
Waytoeasylearn 
Waytoeasylearn 
Welcome 
Welcome 
Waytoeasylearn 
Welcome 
Waytoeasylearn

Run in playground

Starting multiple Goroutines

Let us write one more program that starts multiple Goroutines.

package main

import (
    "fmt"
    "time"
)

func numbers() {
    for i := 1; i <= 5; i++ {
        time.Sleep(300 * time.Millisecond)
        fmt.Printf("%d ", i)
    }
}

func alphabets() {
    for i := 'a'; i <= 'e'; i++ {
        time.Sleep(400 * time.Millisecond)
        fmt.Printf("%c ", i)
    }
}

func main() {
    go numbers()
    go alphabets()
    time.Sleep(3000 * time.Millisecond)
    fmt.Println("Main terminated")
}
1 a 2 b 3 4 c 5 d e main terminated

Run in playground

The above program starts with 2 Goroutines. These two Goroutines now run concurrently. The numbers Goroutine sleeps initially for 300 milliseconds and then prints 1, then sleeps again and prints 2 and the same cycle happens till it prints 5.

Similarly, the alphabets Goroutine prints alphabets from a to e and has 400 milliseconds sleep time. The main Goroutine initiates the numbers and alphabets Goroutines, sleeps for 3000 milliseconds and then terminates.

Advantages of Goroutines
  • Goroutines are cheaper than threads.
  • These are stored in the stack, and the size of the stack can grow and shrink according to the program’s requirement. But in threads, the size of the stack is fixed.
  • Goroutines can communicate using the channel, and these channels are specially designed to prevent race conditions when accessing shared memory using Goroutines.
  • Suppose a program has one thread, and that thread has many Goroutines associated with it. If any of Goroutine blocks the thread due to resource requirements, all the remaining Goroutines will be assigned to a newly created OS thread. All these details are hidden from the programmers.
Anonymous Goroutine

In the Go language, you can also start Goroutine for an anonymous function or in other words, you can create an anonymous Goroutine simply by using the go keyword as a prefix of that function.

package main

import (
	"fmt"
	"time"
)

func main() {

	fmt.Println("Welcome to Main function")

	// Creating Anonymous Goroutine
	go func() {

		fmt.Println("Welcome to Waytoeasylearn")
	}()

	time.Sleep(1 * time.Second)
	fmt.Println("GoodBye to Main function")
}

Output

Welcome to Main function 
Welcome to Waytoeasylearn 
GoodBye to Main function

Run in playground

Goroutines
Scroll to top