This article is translated

The original address: golangbot.com/goroutines/

In this tutorial, we will discuss how to implement concurrency in Go using Goroutines.

What are Goroutines?

A Goroutine is a function or method that runs in parallel with other functions or methods. Goroutines can be considered lightweight threads. The cost of creating a Goroutine is small compared to threads. Therefore, it is common for Go applications to run thousands of Goroutines simultaneously.

Advantages of Goroutines over threads

  • Goroutines take up very little memory compared to threads. They have a stack size of only a few kilobytes, and the stack can expand and shrink according to the needs of the application, whereas for threads, the stack size must be specified and fixed.
  • Goroutines are multiplexed to fewer OS threads. In a program with thousands of Goroutines, there may be only one thread. If any Goroutines in the thread block say they are waiting for user input, another OS thread is created and the remaining Goroutines are moved to the new OS thread. All of this is handled carefully by the runtime, and as programmers we abstract away from these intricate details and provide them with clean apis to work with concurrency.
  • Goroutine uses channels to communicate. By designing channels, you can prevent contention when accessing shared memory using Goroutines. You can think of a channel as a channel that communicates using a Goroutine. In the next tutorial, we’ll discuss channels in detail.

How do I start a Goroutines?

Using the keyword go prefix function or method calls, you will run a new Goroutine at the same time.

Create a Goroutines:

package main

import (  
    "fmt"
)

func hello(a) {  
    fmt.Println("Hello world goroutine")}func main(a) {  
    go hello()
    fmt.Println("main function")}Copy the code

Go Hello () will create a new Goroutines. Now the hello() function will run concurrently with the main() function. The main function runs in its own Goroutine and is called the main Goroutine.

Run the program and you’ll be surprised!

This program outputs only the text main function. What happened to the Goroutine we created at the beginning? We need to understand two main properties of the GO coroutine to understand why this happens.

  • When a new Goroutine is started, the Goroutine call returns immediately. Unlike functions, controls do not wait for Goroutine to complete execution. After a Goroutine call, the control is immediately returned to the next line of code, and all return values in the Goroutine are ignored.
  • The main Goroutine should be running before any other Goroutine can run. If the main Goroutine terminates, the program terminates, and no other Goroutine runs.

I think you will now be able to understand why our Goroutine is not running. After the first call to Hello (). The control immediately returns to the next line of code without waiting for the Hello Goroutine to finish and print the main Function. Then, because there is no other code to execute, the main Goroutine terminates, so the Hello Goroutine doesn’t get a chance to run.

Let’s solve this problem now.

package main

import (  
    "fmt"
    "time"
)

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

In the program above, we call the time package’s Sleep method, which will Sleep the go coroutine executing. In this case, the main goroutine goes to sleep for one second. The call to Go Hello () now has enough time to execute before the main Goroutine terminates. The program prints the Hello World Goroutine, waits for 1 second, and then prints the main Function.

The way we use sleep in the main Goroutine to wait for other Goroutines to finish executing is one of the tricks we use to understand how Goroutine works. A channel can be used to block the primary Goroutine until all other Goroutines have finished executing. We will discuss this in the next tutorial.

Start multiple Goroutines

Let’s write another program that launches multiple Goroutines to better understand Goroutine.

package main

import (  
    "fmt"
    "time"
)

func numbers(a) {  
    for i := 1; i <= 5; i++ {
        time.Sleep(250 * time.Millisecond)
        fmt.Printf("%d ", i)
    }
}
func alphabets(a) {  
    for i := 'a'; i <= 'e'; i++ {
        time.Sleep(400 * time.Millisecond)
        fmt.Printf("%c ", i)
    }
}
func main(a) {  
    go numbers()
    go alphabets()
    time.Sleep(3000 * time.Millisecond)
    fmt.Println("main terminated")}Copy the code

Two Goroutines are launched in the above program. Both goroutines run at the same time. Numbers Goroutine initially sleeps for 250 milliseconds, then prints 1, then sleeps again and prints 2, and the same cycle occurs until 5 is printed. Similarly, Alphabets Goroutine prints letters from A to E and has a sleep time of 400 milliseconds. The master Goroutine starts numbers and Alphabets Goroutine, sleeps for 3000 milliseconds, and then terminates.

Program output:

1 a 2 3 b 4 c 5 d e main terminated  
Copy the code

The following diagram depicts how the program works. Open the image in a new TAB for better visibility 🙂

The first part of the image is blue, representing Numbers Goroutine, the second part is maroon, representing Alphabets Goroutine, the third part is green, representing master Goroutine, and the final part is black, combining the above three parts and showing us how the program works. Strings like 0 ms at the top of each box, 250 ms represent the time in milliseconds, and the output at the bottom of each box is 1, 2, 3, and so on. The bottom of the last black box has values 1, A, 2, 3, B, 4, C, 5, D, e which are the main terminations and the output of the program. The image is self-explanatory and you’ll be able to see how the program works.