Mutex RWMutex отличия?

Mutex и RWMutex являются двумя разными типами синхронизации в языке программирования Go, которые могут быть использованы для решения проблем с параллелизмом и доступом к общим ресурсам.

Mutex
Mutex (Mutual Exclusion) является простым механизмом блокировки, который позволяет только одной горутине получить доступ к критической секции кода в определенный момент времени. Если горутина заблокировала Mutex, то остальные горутины будут ожидать до тех пор, пока Mutex не будет освобожден.

В Go, чтобы использовать Mutex, нужно сначала создать экземпляр типа Mutex с помощью функции sync.NewMutex(). Затем, перед тем как горутина может получить доступ к критической секции кода, она должна вызвать метод Lock() на Mutex. Это обозначает начало использования Mutex и блокировку других горутин. После выполнения работы внутри критической секции кода, горутина вызывает метод Unlock(), чтобы освободить Mutex, позволяя другим горутинам получить доступ к критической секции кода.

Пример использования Mutex в Go:

import (
    "sync"
    "fmt"
)

var counter int
var mutex sync.Mutex

func increment() {
    mutex.Lock()
    counter++
    mutex.Unlock()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            increment()
        }()
    }
    wg.Wait()
    fmt.Println(counter)
}

В этом примере создается глобальный счетчик, к которому несколько горутин параллельно обращаются. Счетчик инкрементируется внутри критической секции, защищенной Mutex. Благодаря использованию Mutex, гарантируется, что только одна горутина будет обращаться к счетчику одновременно, предотвращая возможные проблемы с одновременным доступом.

RWMutex
RWMutex (Reader-Writer Mutex) предоставляет более гибкую семантику блокировки, чем обычный Mutex. RWMutex позволяет множеству горутин получить параллельный доступ для чтения (блокировка чтения), но только одной горутине получить эксклюзивный доступ на запись (блокировка записи).

Зачем это может быть полезно? Если у вас есть часть кода, которая только считывает какие-то данные, вы можете использовать RWMutex для разрешения параллельных чтений без блокировки других горутин. Однако, если одна или несколько горутин пытаются изменить данные, они должны сначала установить эксклюзивную блокировку записи, чтобы предотвратить другие горутины взаимодействовать с данными в то время как они в процессе изменения.

В Go, чтобы использовать RWMutex, нужно создать экземпляр типа RWMutex с помощью функции sync.NewRWMutex(). Затем, чтобы получить блокировку чтения, горутина вызывает метод RLock() на RWMutex. Это позволяет нескольким горутинам читать одновременно. Чтобы получить блокировку записи, горутина вызывает метод Lock(). Это блокирует другие горутины, пока не будет освобождена блокировка записи с помощью метода Unlock().

Пример использования RWMutex в Go:

import (
    "sync"
    "fmt"
)

var counter int
var rwMutex sync.RWMutex

func read() {
    rwMutex.RLock()
    fmt.Println(counter)
    rwMutex.RUnlock()
}

func write() {
    rwMutex.Lock()
    counter++
    rwMutex.Unlock()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(2)
        go func() {
            defer wg.Done()
            read()
        }()
        go func() {
            defer wg.Done()
            write()
        }()
    }
    wg.Wait()
}

В этом примере создается глобальный счетчик, которым несколько горутин одновременно читают и одна горутина инкрементирует. Метод read() получает блокировку чтения на RWMutex, позволяя нескольким горутинам одновременно читать значение счетчика. Метод write() получает блокироку записи на RWMutex, позволяя только одной горутине изменять значение счетчика.

В заключение, Mutex предлагает простой механизм блокировки, позволяющий только одной горутине получить доступ к критической секции кода, в то время как RWMutex предлагает более гибкую семантику блокировки, которая позволяет множеству горутин получать доступ для чтения, но только одной горутине получить доступ для записи. В зависимости от конкретной задачи, вы можете использовать один из этих механизмов блокировки или комбинировать их вместе для достижения необходимой функциональности и производительности в вашей программе на Go.