Мы видели, насколько хорошо каналы подходят для связи между go-процедурами.
Но что если нам не нужна связь? Что если мы только хотим убедиться, что, во избежание конфликтов, только одна go-процедура имеет доступ к переменной в любой момент времени?
Эта концепция известна как взаимное исключение, и общепринятым названием для структуры данных, которая это позволяет, является мьютекс (mutex).
Стандартная библиотека Go предоставляет взаимное исключение с помощью sync.Mutex и двух его методов:
Lock
Unlock
Мы можем объявить блок кода, который будет выполняться при взаимном исключении, окружив его вызовами к Lock и Unlock, как показано в методе Inc.
Мы также можем использовать defer, чтобы удостовериться, что мьютекс будет освобожден, как в методе Value.
package main
import (
"fmt"
"sync"
"time"
)
// SafeCounter безопасен для конкурентного использования.
type SafeCounter struct {
v map[string]int
mux sync.Mutex
}
// Inc инкрементирует счетчик для переданного ключа.
func (c *SafeCounter) Inc(key string) {
c.mux.Lock()
// Вызван Lock, поэтому только одна go-процедура за раз
// может получить доступ к карте c.v
c.v[key]++
c.mux.Unlock()
}
// Value возвращает текущее значение счетчика
// для переданного ключа.
func (c *SafeCounter) Value(key string) int {
c.mux.Lock()
// Вызван Lock, поэтому только одна go-процедура за раз
// может получить доступ к карте c.v
defer c.mux.Unlock()
return c.v[key]
}
func main() {
c := SafeCounter{v: make(map[string]int)}
for i := 0; i < 1000; i++ {
go c.Inc("somekey")
}
time.Sleep(time.Second)
fmt.Println(c.Value("somekey"))
}
Вывод:
1000
Читайте также:
- Основы языка Go: Go-процедуры (goroutines)
- Основы языка Go: каналы
- Основы языка Go: буферизированные каналы
Комментариев нет:
Отправить комментарий