Sling Academy
Home/Golang/Combining Channels and Mutexes for Hybrid Concurrency Models in Go

Combining Channels and Mutexes for Hybrid Concurrency Models in Go

Last updated: November 27, 2024

Introduction to Hybrid Concurrency in Go

Go (or Golang) is a language that has become incredibly popular for building concurrent software. Its concurrency model is built around the concept of goroutines and channels. While goroutines allow you to run functions concurrently, channels are used for communication between these goroutines. This article explores how you can combine channels with mutexes to achieve a hybrid concurrency model.

Understanding Goroutines and Channels

Goroutines are functions or methods that run concurrently with other functions. Channels, on the other hand, are a way for goroutines to communicate.


package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world")  // This runs as a goroutine
    say("hello")     // This runs in the main goroutine
}

Basic Channel Example

Here’s how you can make use of channels for communication between goroutines:


package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum  // Send sum to channel c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)

    x, y := <-c, <-c  // Receive from channel c

    fmt.Println(x, y, x+y)
}

Introducing Mutexes

A Mutex allows you to lock data so that only one goroutine at a time can access it. This is needed when you have shared resources that could be accessed and modified concurrently, leading to race conditions.


package main

import (
    "fmt"
    "sync"
)

var (
    counter int
    mu      sync.Mutex
)

func increment(wg *sync.WaitGroup) {
    defer wg.Done()
    mu.Lock()          // Lock the shared variable
    counter++
    mu.Unlock()        // Unlock after incrementing
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go increment(&wg)
    }

    wg.Wait()
    fmt.Println("Final Counter:", counter)
}

Combining Channels and Mutexes

Sometimes, you need both communication as well as protection of shared data. This is where the combination of channels and mutexes becomes powerful.


package main

import (
    "fmt"
    "sync"
)

func producer(c chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        c <- i
    }
}

func consumer(c chan int, results *[]int, mu *sync.Mutex, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        value := <-c
        mu.Lock()
        *results = append(*results, value)
        mu.Unlock()
    }
}

func main() {
    c := make(chan int)
    var wg sync.WaitGroup
    var results []int
    var mu sync.Mutex

    wg.Add(1)
    go producer(c, &wg)

    wg.Add(1)
    go consumer(c, &results, &mu, &wg)

    wg.Wait()
    fmt.Println("Results:", results)
}

Conclusion

By understanding how to effectively combine channels and mutexes, you can leverage the strengths of both concurrency models in Go. Channels enable goroutines to safely communicate with each other, while mutexes provide a straightforward solution for managing access to shared data. Using these tools together can significantly enhance the efficiency and safety of concurrent applications in Go.

Next Article: Concurrency Challenges: Writing an Async Task Manager in Go

Previous Article: Using Go's Scheduler for Load Balancing Tasks

Series: Concurrency and Synchronization in Go

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant