Мы видели, насколько хорошо каналы подходят для связи между 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: буферизированные каналы

Комментариев нет:
Отправить комментарий