GO mutex -pt2

RW MUTEX

The standard library also exposes a sync.RWMutex.

By using a sync.RWMutex, our program becomes more efficient. We can have as many readLoop() threads as we want, while still ensuring that the writers have exclusive access.

In addition to these methods:

the sync.RWmutex also has these methods:

Thesync.RWmutexcan help withperformance if we have aread-intensive process. Manygoroutines can safely read from the map at the same time (multiple RLock() calls can happen simultaneously). However, only one goroutine can hold a Lock() and all RLock()'s will also be excluded.

package main

import (
    "fmt"
    "sort"
    "sync"
    "time"
)

type safeCounter struct {
    counts map[string]int
    mu     *sync.RWMutex
}

func (sc safeCounter) inc(key string) {
    sc.mu.Lock()
    defer sc.mu.Unlock()
    sc.slowIncrement(key)
}

func (sc safeCounter) val(key string) int {
    sc.mu.RLock()
    defer sc.mu.RUnlock()
    return sc.counts[key]
}

// don't touch below this line

func (sc safeCounter) slowIncrement(key string) {
    tempCounter := sc.counts[key]
    time.Sleep(time.Microsecond)
    tempCounter++
    sc.counts[key] = tempCounter
}

type emailTest struct {
    email string
    count int
}

func test(sc safeCounter, emailTests []emailTest) {
    emails := make(map[string]struct{})

    var wg sync.WaitGroup
    for _, emailT := range emailTests {
        emails[emailT.email] = struct{}{}
        for i := 0; i < emailT.count; i++ {
            wg.Add(1)
            go func(emailT emailTest) {
                sc.inc(emailT.email)
                wg.Done()
            }(emailT)
        }
    }
    wg.Wait()

    emailsSorted := make([]string, 0, len(emails))
    for email := range emails {
        emailsSorted = append(emailsSorted, email)
    }
    sort.Strings(emailsSorted)

    sc.mu.RLock()
    defer sc.mu.RUnlock()
    for _, email := range emailsSorted {
        fmt.Printf("Email: %s has %d emails\n", email, sc.val(email))
    }
    fmt.Println("=====================================")
}

func main() {
    sc := safeCounter{
        counts: make(map[string]int),
        mu:     &sync.RWMutex{},
    }
    test(sc, []emailTest{
        {
            email: "john@example.com",
            count: 23,
        },
        {
            email: "john@example.com",
            count: 29,
        },
        {
            email: "jill@example.com",
            count: 31,
        },
        {
            email: "jill@example.com",
            count: 67,
        },
    })
    test(sc, []emailTest{
        {
            email: "kaden@example.com",
            count: 23,
        },
        {
            email: "george@example.com",
            count: 126,
        },
        {
            email: "kaden@example.com",
            count: 31,
        },
        {
            email: "george@example.com",
            count: 453,
        },
    })
}