What are Goroutines?
A goroutine is a lightweight thread managed by the Go runtime.
How to start a Goroutine
You can declare a goroutine by adding the keyword go before a function or method invocation like the code below.
go function_name(arg, ...)
In the following code, go hello() starts a new goroutine and hello() will run concurrently along with the main function which runs in its own Goroutine and its called the main Goroutine
package main
import "fmt"
func hello() {
fmt.Println("Hello World")
}
func main() {
go hello()
fmt.Println("main function")
//=> main function
}
The code above only outputs main function. This is due to the following reasons.
Firstly, when a new goroutine starts running, the goroutine call returns immediately. It does not wait for the goroutine to finish executing.
Secondly, the main Goroutine should be running for any other goroutines to run. If the main goroutine terminates, the program will be terminated and no other goroutine will run.
Now you understand why it didn't output Hello World. In the code, after calling go hello(), the control returned immediately to the next line of code which is fmt.Println("main function") without waiting for the hello goroutine to finish.
You can execute hello() by giving it enough time to run before the main goroutine terminates.
package main
import (
"fmt"
"time"
)
func hello(){
fmt.Println("Hello World")
}
func main(){
go hello()
time.Sleep(1 * time.Second)
fmt.Println("main function")
//=> Hello World
//=> main function
}
Normaly, channels are used to block the main goroutine until all other goroutines finish their execution.
How to check the number of all existing goroutines
You can use runtimeNumGoroutine() to get all the existing goroutines in your code.
package main
import (
"log"
"runtime"
"fmt"
)
func hello(){
fmt.Println("Hello World")
}
func main(){
go hello()
fmt.Println("main function")
log.Println(runtime.NumGoroutine()) //-> 2018/10/09 07:39:07 2
}
Channels
Channels provide a way for goroutines to communicate with one another and synchronize their execution. Data can be sent from one goroutine and received from another goroutine.
How to declare a channel
You can declare a channel like the code below.
ch := make(chan TYPE)
Each channel has a type associated with it. This type is the type of data that the channel is allowed to transport. You can not transport any other data using the channel.
Sending and receiving from a channel
You can send and receive data from a channel using the syntax below.
ch <- data // write to channel ch
variable := <- cd // read from channel ch
In the first line, the arrow points towards ch and this means we are writing data to channel ch.
In the second line, the arrow points outwards from ch and this means we are reading from ch and storing data to variable.
package main
import "fmt"
func main() {
//Create a new channel
ch := make(chan string)
//Write data to ch
go func() { ch <- "data" }()
//Reading data from ch
variable := <-ch
fmt.Println(variable) //=> data
}
Sends and receives are blocking by default
By default, sends and receives block until the other side is ready. That means when a data is sent to a channel, the control is blocked until some other goroutine reads from that channel.
This allows goroutines to synchronize without explicit locks or condition variables.
Example1
In the following code, I created a boolean type channel named ch and declare a function as a goroutine. Then, I passed a boolean value to ch in the function.
The <-ch statement will block the code until some boolean data is received on the ch channel.
package main
import "fmt"
func main() {
ch := make(chan bool) //Create a boolean type channel
//Run the following function as a goroutine.
go func() {
fmt.Println("Hello")
ch <- true //Pass a boolean value to the channel
}()
<- ch //Block until ch receives a boolean value
}
Example2
In this example, I defined a function called hello which accepts a channel as its argument. And then, I created a channel called ch in the main goroutine and passed it as a parameter to the hello() goroutine.
Like Example1, the <-ch statement will block the code until some boolean data is received on the ch channel.
package main
import "fmt"
func hello(channel chan bool) {
fmt.Println("Hello world")
channel <- true
}
func main() {
ch := make(chan bool) //Create a boolean type channel
go hello(ch) //Run hello method as a goroutine
<-ch //Block until ch receives a boolean value
fmt.Println("main function")
//=> Hello world
// main function
}
More Resources
GOLANGBOT.COM
Go Resources (Concurrency)
A Tour of Go (Goroutines)
Top comments (5)
Great series!
Thank you!
When the myFunction() is called, a new goroutine is created and the code within the function is executed concurrently with the main program. blossom word game
It spawns a new goroutine, allowing the code within the function to run concurrently with the main program. doramasqueen
Thank you for your plan. I have learned a lot。
sms activate