Go by Example: RWMutex
Optimize concurrent access with RWMutex (Read-Write Mutex). This example shows how to use `sync.RWMutex` to allow multiple concurrent readers while ensuring exclusive access for writers, a pattern that significantly improves performance for read-heavy workloads.
Code
package main
import (
"fmt"
"math/rand"
"sync"
"sync/atomic"
"time"
)
func main() {
// Map state protected by RWMutex
var state = make(map[int]int)
var mutex = &sync.RWMutex{}
// Track operation counts
var readOps uint64
var writeOps uint64
// Start 100 goroutines to read the state repeatedly
for r := 0; r < 100; r++ {
go func() {
for {
// RLock() allows multiple simultaneous readers
// but blocks if a writer has the lock
mutex.RLock()
total := 0
for _, v := range state {
total += v
}
// RUnlock() releases the read lock
mutex.RUnlock()
atomic.AddUint64(&readOps, 1)
time.Sleep(time.Millisecond)
}
}()
}
// Start 10 goroutines to write to the state
for w := 0; w < 10; w++ {
go func() {
for {
key := rand.Intn(5)
val := rand.Intn(100)
// Lock() requests exclusive access for writing
// Blocks all other readers and writers
mutex.Lock()
state[key] = val
mutex.Unlock()
atomic.AddUint64(&writeOps, 1)
time.Sleep(time.Millisecond)
}
}()
}
// Let the goroutines work for a second
time.Sleep(time.Second)
// Report final operation counts
readOpsFinal := atomic.LoadUint64(&readOps)
writeOpsFinal := atomic.LoadUint64(&writeOps)
fmt.Printf("Total operations:\nReads: %d\nWrites: %d\n",
readOpsFinal, writeOpsFinal)
}Explanation
A standard Mutex locks out all other goroutines, whether they want to read or write. However, it's safe for multiple goroutines to read the same memory simultaneously, as long as no one is writing to it. sync.RWMutex (Read-Write Mutex) solves this inefficiency.
RWMutex has two sets of methods: Lock/Unlock for writers (exclusive access) and RLock/RUnlock for readers (shared access). This allows many readers to access the data concurrently, significantly improving performance for read-heavy workloads.
Key differences from Mutex:
- Use RLock() when you only need to read data
- Use Lock() when you need to modify data
- Multiple RLock() calls can happen simultaneously
- Lock() blocks until all readers are finished

