Goroutines in Golang


January 17, 2022, Learn eTutorial
1326

In this tutorial, you will learn about Goroutines used in the Go programming language. In Golang Goroutine is used for achieving Golang concurrency. So we will first understand an overview of what is concurrency, how to achieve concurrency, uses of Goroutine, and so on.

What is concurrency in Golang?

  • Concurrency is the ability of different segments or units of a program or an algorithm to execute independently without affecting the terminal(final) output of the program.
  • When a program is broken down into different segments say “n “no of segments or parts.
  • The final output should not depend on how these “n” segments are executed.
     

Benefit of concurrency

  • Concurrency allows the parallel execution of concurrent units.
  • It improves the overall speed/performance of execution.
     

Let us understand the concept in a simpler way. Consider the mathematical expression

(4+ 2) *(1+4)
We can solve this expression in 3 steps  

GO :Goroutine

Another way of calculating the same expression is

GO :Goroutine

From this mathematical expression example, we can infer that the final output will remain unchanged even though the order of execution differs.
Concurrency is achieved through threads.

What is a thread in Golang?

In go programming language Goroutine is a lightweight thread that is controlled by go runtime. Goroutine is similar to threads as in any other programming language. Go threads are also known as “Green threads”. Green threads are simply threads that are not managed by an underlying OS (operating system) but are managed either by a user program or user library or in some other ways.

What is Goroutine in Golang?

In Golang concurrently executing actions in a program is known as Goroutines. Besides using huge and resource-intensive threads, Golang creates an abstraction of a thread that is called a Goroutine. Go runtime has a scheduler that maps Goroutine to OS threads for a certain period of time.

Note: Programmers do not interact with low-level threads but do interact with high-level Goroutine provided by Golang runtime.

Consider a simple program with

  • main function main() which prints “go program starts” & “go program end”
  • inside main () calls hello(1) function with argument 1 of integer data type.
  • When the program starts its execution control starts from main when it sees hello() jumps to code where hello statement is declared and initialized.
  • The hello() function prints hello 5 times given inside a for loop
  • When the loop ends control goes back to the main & print “go program end “ statement.

package main
import "fmt"

func main() {
 fmt.Println("Go program starts")
    hello(1)
    fmt.Println("Go program ends")
    }
  
  func hello(word int){
  for i :=0; i<5 ; i++ {
      fmt.Println(word,"hello ")
      }
      }

Output:


Go program starts
1 hello 
1 hello 
1 hello 
1 hello 
1 hello 
Go program ends

Difference between thread & Goroutine in Golang?

Thread Goroutine
Threads are managed by operating systems. Goroutine methods are managed by Golang runtime
Thread is dependent on hardware Goroutine is independent of hardware.
Thread does not have an easy communication medium. Goroutines have an easy communication medium known as a channel.
Threads do not have growable segmented stacks. Goroutine has growable segmented stacks.
Threads are preemptively scheduled. Goroutines are co-operatively scheduled

How to introduce Goroutine in Golang?

Now you are going to learn how Goroutine is introduced in a Go program & what changes will it cause in the above program.
Syntax for Goroutine


func  main (){
      …….
                go f(a,b)       //go keyword
}
                func  f(a,b){
} 

The keyword go defines a Goroutine statement in a normal function or method.

  •   go f(a,b) starts a new Goroutine running f(a,b).
  •   The function f (a,b) is evaluated within the current Goroutine and the execution off happens in the new Goroutine.
     

In the above program, we introduced a new keyword called go to make this program concurrent .when the normal hello(1) function is replaced with go hello (1).

The hello (1) function which was executed sequentially in the above program will start executing in a separate Goroutine of its own. When you run the code it just prints the two print statements given inside the main () function. Even though the hello (1) function is called no output is visible in the console.  

Let us see the program with output for the same.


package main
import "fmt"

func main() {
 fmt.Println("Go program starts")
    go hello(1)  
    fmt.Println("Go program ends")
    }
  
  func hello(word int){
  for i :=0; i<5 ; i++ {
      fmt.Println(word,"hello ")
      }
      }

Output:


Go program starts
Go program ends

The reason why the hello(1) function is not displayed?

This is because the main() function or main Goroutine terminated before hello(1) function execution.

What is the solution for early termination of the main () function or main Goroutine?

The solution to solve this is to make the main Goroutine sleep for some time. For making it happen we need to provide a new statement to the above program 

time.Sleep(100 * time.Millisecond)

let us understand with a program where sleep is included.  


package main
import (
  "fmt"
  "time"
)

func main() {
 fmt.Println("Go program starts")
    go hello(1)  
    fmt.Println("Go program ends")
    time.Sleep(100 * time.Millisecond)
    }
  
  func hello(word int){
  for i :=0; i<5 ; i++ {
      fmt.Println(word,"hello ")
      }
      }

Output:


Go program starts
Go program ends
1 hello 
1 hello 
1 hello 
1 hello 
1 hello

After running the code we get two Goroutines

  1. main() Goroutine output 

    Output:

    
    Go program starts
    Go program ends
    
  2. the output of Goroutine running hello(1) function

    Output:

    
    1 hello 
    1 hello 
    1 hello 
    1 hello 
    1 hello
    

In Golang there is no need to extend the thread class, no need to implement any runnable class as in other programming languages.
A 3 keystroke ie go <space> is sufficient to achieve concurrency. 

Anonymous function in Goroutine

In the below program an unnamed function known as an anonymous function is declared & is called there itself. The opening and closing braces {} just after the function indicates the function call itself.

//Program Heading. If there is no heading remove h3 tag


msg :="learn eTutorial"
go func(){
              fmt.Println(msg)
}()

 

When we run the below code the output of the function is as shown in the output session.ie


Go program starts
Go program ends
learn eTutorial

The program shows the anonymous function


package main
import (
  "fmt"
  "time"
)

func main() {
 fmt.Println("Go program starts")
    
    msg :="learn eTutorial"
    go func(){  //anonymous function
    fmt.Println(msg)
    }()
   
    fmt.Println("Go program ends")
    time.Sleep(100 * time.Millisecond)
    }

Output:


Go program starts
Go program ends
learn eTutorial

Next, let us see what happens when the msg variable value is changed after the function.
msg :="learn eTutorial"
go func(){
              fmt.Println(msg)
}()
               msg := “hello users”


package main
import (
  "fmt"
  "time"
)

func main() {
 fmt.Println("Go program starts")
    
    msg :="learn eTutorial"
    go func(){  //anonymous function
    fmt.Println(msg)
    }()
    msg = "hello users"
    fmt.Println("Go program ends")
    time.Sleep(100 * time.Millisecond)
    }

Output:


Go program starts
Go program ends
hello users

The output gets modified due to the addition of the last statement in the function. Compare the output of both programs discussed above.

What is a race condition in Goroutine?

In the just previous code, we introduced a race condition. The same code is accessed from the main Goroutine as well as for the Goroutine in the anonymous function.

GO : GOroutine

In the general race, conditions are not safe to use inside programs because it results in so many bugs or errors.

Advantages of Goroutine

  •   Goroutine can be started with a very small stack space.
  •   Goroutine can be easily created or destroyed
  •   Goroutine can be reallocated quickly. 
  •   Go applications can have 1000s of Goroutines.