- Published on
GoLang Concurrency Patterns
- Authors
- Name
- Avinash
Writing Concurrent Programs in GoLang
Welcome back to our GoLang series! In this blog post, we'll explore concurrency patterns in GoLang and learn how to write concurrent programs. Concurrency is a powerful feature that enables programs to execute multiple tasks simultaneously, leading to increased performance and responsiveness. Let's dive in!
Mutex
One of the fundamental concurrency patterns in GoLang is the use of mutexes to synchronize access to shared resources. A mutex, short for mutual exclusion, allows only one Goroutine to access the shared resource at a time.
Here's an example of using a mutex to protect a shared counter:
package main
import (
"fmt"
"sync"
)
type Counter struct {
value int
mutex sync.Mutex
}
func (c *Counter) Increment() {
c.mutex.Lock()
c.value++
c.mutex.Unlock()
}
func (c *Counter) GetValue() int {
c.mutex.Lock()
defer c.mutex.Unlock()
return c.value
}
func main() {
counter := Counter{}
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
counter.Increment()
wg.Done()
}()
}
wg.Wait()
fmt.Println("Counter value:", counter.GetValue())
}
In this example, we define a Counter struct that contains a value and a mutex. The Increment method locks the mutex, increments the value, and unlocks the mutex. The GetValue method also locks and unlocks the mutex when accessing the value.
By using a mutex, we ensure that only one Goroutine can access the shared counter at a time, preventing data races and ensuring consistent results.
WaitGroup
The sync.WaitGroup type provides a simple way to wait for multiple Goroutines to complete their execution. It allows you to wait until all Goroutines finish before proceeding to the next steps.
Here's an example of using a WaitGroup to wait for Goroutines:
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d started\n", id)
// Simulate some work
for i := 0; i < 3; i++ {
fmt.Printf("Worker %d is working\n", id)
}
fmt.Printf("Worker %d completed\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers completed")
}
In this example, we define a worker function that performs some work. We pass a pointer to the WaitGroup to each Goroutine and call wg.Done() to signal the completion of the Goroutine. The main function waits for all the Goroutines to finish by calling wg.Wait().
By utilizing the WaitGroup, we can ensure that all Goroutines complete their execution before proceeding.
Select Statement with Channels
The select statement combined with channels is a powerful pattern in GoLang for handling multiple concurrent operations. It allows you to wait on multiple channel operations and proceed when any of them is ready.
Here's an example of using the select statement with channels:
package main
import (
"fmt"
"time"
)
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(2 * time.Second)
c1 <- "Hello from c1"
}()
go func() {
time.Sleep(1 * time.Second)
c2 <- "Hello from c2"
}()
for i := 0; i < 2; i++ {
select {
case msg := <-c1:
fmt.Println("Received from c1:", msg)
case msg := <-c2:
fmt.Println("Received from c2:", msg)
}
}
}
In this example, we create two channels c1 and c2 and launch Goroutines to send messages to these channels after a certain delay. The select statement listens to both channels and proceeds as soon as any of the channels has a message. We print the received messages accordingly.
The select statement with channels allows you to handle multiple concurrent operations effectively.
Conclusion
Congratulations on learning about concurrency patterns in GoLang! In this blog post, we explored the use of mutexes for synchronizing access to shared resources, the WaitGroup for coordinating Goroutines, and the select statement with channels for handling multiple concurrent operations. By leveraging these patterns, you can write efficient and concurrent programs in GoLang.
In the next blog post, we'll delve into error handling in concurrent GoLang programs and explore techniques to handle errors effectively in concurrent scenarios. Stay tuned!