среда, 16 января 2019 г.

Основы Go: sync.Mutex

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


Читайте также:


Комментариев нет:

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