Go routines are lightweight, concurrent execution units managed by the Go runtime. They are similar to threads but have much lower overhead in terms of memory and allow you faster concurrent processing than threads. Go routines are one of the key features of Go, enabling programmers to write concurrent code efficiently and simply.
When using Go routines, you can achieve parallelism without explicitly dealing with threads, mutexes, or semaphores, which is a common source of complexity and bugs in concurrent programming.
Here’s how Go routines work and how to use them:
1. A Go routine is created when you call a function with the ‘go‘ keyword, which runs the function concurrently with the rest of the program.
go funcName(parameters)
2. Go runtime multiplexes all Go routines onto a smaller number of threads, often just a single thread per available CPU core. Due to their small stack size (usually around 2-8 KB), you can create and manage a large number of Go routines.
3. Communication and synchronization between Go routines are achieved through channels, which are typed conduits that allow sending and receiving values.
Here’s a simple example of using Go routines:
package main
import (
"fmt"
"time"
)
func printNumber(number int) {
fmt.Println(number)
}
func main() {
go printNumber(1)
go printNumber(2)
time.Sleep(time.Second)
}
In the example above, we create two Go routines by invoking ‘printNumber‘ function with the ‘go‘ keyword. The ‘time.Sleep‘ is used just to allow enough time for our Go routines to execute, otherwise, the ‘main‘ function might finish before Go routines have a chance to run.
However, ‘time.Sleep‘ is not the recommended way to orchestrate Go routines. The idiomatic way to achieve synchronization between concurrent functions in Go is using channels. Here’s an example using channels:
package main
import "fmt"
func sayHello(ch chan string) {
ch <- "Hello from Go routine!"
}
func main() {
messageChannel := make(chan string)
go sayHello(messageChannel)
message := <-messageChannel
fmt.Println(message)
}
In this example, we create a new channel ‘messageChannel‘ of type ‘chan string‘. Inside the ‘sayHello‘ function, we send a string "Hello from Go routine!" to this channel. Then, in the main function, we receive the message from the channel and print it.
When using channels in Go, it’s important to remember that channel operations can block. For example, sending a value to a channel will block until a value is received, and receiving a value from a channel will block until a value is sent.
In summary, Go routines are a powerful way to achieve concurrent programming in Go. They offer an efficient and easy-to-use abstraction for running functions concurrently, and the use of channels for communication and synchronization provides a clean, idiomatic approach to concurrent programming.