DevGang
Авторизоваться

Что такое мьютекс в Golang?

Создавая программы на Golang, вы почти всегда найдете применение горутинам.

Горутины мощны и в целом просты в использовании, однако, если вам нужно изменить часть данных, которые совместно используются между горутинами, то вы можете столкнуться с проблемами целостности данных.

В этой статье мы рассмотрим, что такое мьютекс и как его использовать.

Что такое мьютекс?

В Golang горутина - это, по сути, функция, которая помещается в фоновую очередь и выполняется параллельно при каждом доступном ресурсе.

package main

import (
    "fmt"
    "sync"
)

var NUM_PROCESSED = 0

func countNumProcessed(wg *sync.WaitGroup) {
    defer wg.Done()
    NUM_PROCESSED++
}

func main() {
    var wg sync.WaitGroup

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

    wg.Wait()
    fmt.Println(NUM_PROCESSED)
}

Если убрать ключевое слово "go", то каждый вызов функции "countNumProcessed" будет блокировать цикл и ждать завершения работы этой функции, прежде чем продолжить цикл.

При использовании ключевого слова "go" эти функции будут выполняться параллельно. Это позволит двум или более функциям одновременно изменять переменную.

Если вы запустите этот код несколько раз, то заметите, что общий счет колеблется.

Это происходит потому, что каждая горутина в течение нескольких наносекунд копирует значение "NUM_PROCESSED" в память, чтобы увеличить его и затем обновить переменную.

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

Например: предположим, что значение было "200", каждая из двух горутин добавит "1", и получится "201". Таким образом, значение "NUM_PROCESSED" станет "201", а не "202".

Вот тут-то и пригодится мьютекс. Мьютекс создаст "блокировку" в процессе - таким образом, только одна горутина сможет обновить значение "NUM_PROCESSED" за один раз.

Другие горутины будут приостановлены до тех пор, пока блокировка не будет снята. Это очень похоже на очередь - когда каждая горутина снимает блокировку, следующая выполняет новую, и процесс продолжается до тех пор, пока все горутины в очереди не закончат обновление "NUM_PROCESSED".

Пример мьютекса

Мы можем модифицировать приведенный выше код, чтобы ввести мьютекс следующим образом:

package main

import (
    "fmt"
    "sync"
)

var NUM_PROCESSED = 0
var MUTEX sync.Mutex

func countNumProcessed(wg *sync.WaitGroup) {
    defer wg.Done()
    MUTEX.Lock()
    NUM_PROCESSED++
    MUTEX.Unlock()
}

func main() {
    var wg sync.WaitGroup

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

    wg.Wait()
    fmt.Println(NUM_PROCESSED)
}

В приведенном выше коде вы можете заметить, что сколько бы раз вы ни запускали эту функцию, она всегда будет выводить "500". Это ровно столько же, сколько было горутин, созданных в цикле for.

Источник:

#Golang
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу