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.
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
Another way of calculating the same expression is
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.
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.
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
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
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 |
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.
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.
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
Output:
Go program starts Go program ends
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.
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.
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
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.
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.
In the general race, conditions are not safe to use inside programs because it results in so many bugs or errors.