Concurrency in Go
Introduction to Concurrency
Concurrency is the ability of a program to execute multiple tasks at the same time. Go provides built-in support for concurrency, making it efficient and easy to use.
In this article, we will explore the key concurrency features in Go, including goroutines, channels, buffered channels, and the `select` statement.
Goroutines
A goroutine is a lightweight thread managed by the Go runtime. It allows functions to run concurrently, improving performance and responsiveness.
package main
import (
"fmt"
"time"
)
func hello() {
fmt.Println("Hello from goroutine!")
}
func main() {
go hello()
time.Sleep(time.Second) // Allow goroutine to complete
fmt.Println("Main function execution")
}
Here, go hello()
starts a new goroutine to execute the hello
function asynchronously.
Channels
Channels are used to communicate between goroutines safely and efficiently. They help synchronize operations and avoid race conditions.
package main
import "fmt"
func main() {
messages := make(chan string)
go func() {
messages <- "Hello, Go Concurrency!"
}()
msg := <-messages
fmt.Println(msg)
}
In this example, a goroutine sends a message into a channel, and the main function receives and prints it.
Buffered Channels
Buffered channels allow multiple values to be stored before they are received, helping to manage workload efficiently.
package main
import "fmt"
func main() {
messages := make(chan string, 2)
messages <- "Hello"
messages <- "World"
fmt.Println(<-messages)
fmt.Println(<-messages)
}
The buffer size determines how many values can be stored before blocking. In this example, two messages are stored and retrieved sequentially.
Using Select with Channels
The select
statement allows a goroutine to wait on multiple channels, executing the case that is ready first.
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(2 * time.Second)
ch1 <- "Message from ch1"
}()
go func() {
time.Sleep(1 * time.Second)
ch2 <- "Message from ch2"
}()
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
}
Here, the select statement waits for the first available message and executes the corresponding case.
Conclusion
Concurrency in Go makes it easy to execute multiple tasks efficiently using goroutines and channels. By using these features, you can build responsive and high-performance applications.
In the next lesson, we will explore Error Handling in Go, a crucial aspect of writing robust programs.