Fundamentals of Concurrency in Golang
Concurrency is a fundamental concept in Golang (Go) programming, which allows multiple tasks to make progress simultaneously. In Go, concurrency is achieved through the use of goroutines and channels, which provide a powerful and efficient way to write concurrent applications.
Goroutines
Goroutines are lightweight threads of execution that are managed by the Go runtime. They are created using the go
keyword, and can be used to execute functions concurrently. Goroutines are very lightweight and efficient, allowing you to create thousands of them without significant overhead.
package main
import (
"fmt"
"time"
)
func main() {
// Create a new goroutine
go func() {
fmt.Println("Hello from a goroutine!")
}()
// Wait for the goroutine to finish
time.Sleep(1 * time.Second)
}
In the example above, we create a new goroutine that prints a message. The time.Sleep()
function is used to ensure that the main goroutine waits for the new goroutine to finish before exiting.
Channels
Channels are a way for goroutines to communicate with each other. They are created using the make()
function, and can be used to send and receive data between goroutines. Channels provide a synchronization mechanism that allows goroutines to wait for each other and coordinate their activities.
package main
import "fmt"
func main() {
// Create a new channel
ch := make(chan int)
// Send a value to the channel
go func() {
ch <- 42
}()
// Receive a value from the channel
value := <-ch
fmt.Println(value) // Output: 42
}
In the example above, we create a new channel of type int
, and then send a value of 42
to the channel from a new goroutine. We then receive the value from the channel and print it to the console.
Synchronization Primitives
Go also provides a number of synchronization primitives that can be used to coordinate the execution of goroutines. These include mutexes, which can be used to protect shared resources from concurrent access, and wait groups, which can be used to wait for a group of goroutines to finish.
package main
import (
"fmt"
"sync"
)
func main() {
// Create a new wait group
var wg sync.WaitGroup
// Add two goroutines to the wait group
wg.Add(2)
// Run the goroutines
go func() {
defer wg.Done()
fmt.Println("Goroutine 1")
}()
go func() {
defer wg.Done()
fmt.Println("Goroutine 2")
}()
// Wait for the goroutines to finish
wg.Wait()
fmt.Println("All goroutines have finished")
}
In the example above, we create a new sync.WaitGroup
and add two goroutines to it. We then wait for both goroutines to finish using the wg.Wait()
function.