- read

Understanding Golang’s “Do not communicate by sharing memory; instead, share memory by…

Adam Szpilewicz 101

Photo by Gavin Biesheuvel on Unsplash

Golang (Go) is renowned for its straightforward and effective approach to concurrent programming. One of its guiding philosophies is the phrase: “Do not communicate by sharing memory; instead, share memory by communicating.” To truly understand the essence of this philosophy, let’s explore it using Golang examples that illustrate it.

Traditional Approach in Go: Mutex Locks and Shared Memory

Even though Go provides modern concurrency primitives like channels, it still allows for the use of mutex locks for those who prefer a more traditional approach to concurrency. Below the diagram of the sample code that we present right after it.

Example: Summing Numbers Concurrently

Let’s consider a simple task: summing an array of numbers. We can divide this task among multiple Goroutines and have each one sum part of the array. We could use a shared variable to accumulate the total sum, making sure to lock it before each update.

package main

import (
"fmt"
"sync"
)

func main() {
var sum int
var mu sync.Mutex
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var wg sync.WaitGroup
wg.Add(2)

go func() {
for _, n := range numbers[:5] {
mu.Lock()
sum += n
mu.Unlock()
}
wg.Done()
}()

go func() {
for _, n := range numbers[5:] {
mu.Lock()
sum += n
mu.Unlock()
}
wg.Done()
}()
wg.Wait()
fmt.Println("Total Sum:", sum)
}

Issues:

  1. Complexity: We need to remember to lock and unlock the mutex to ensure exclusive access to the sum variable.
  2. Potential for Errors: If you forget to lock or unlock correctly, you’ll run into race conditions.
  3. Reduced Readability: The core logic of summing numbers is interspersed with mutex operations, making the code less straightforward.

The Go Way: Using Channels