Тип atomic.Value

Тип atomic.Value из пакета sync/atomic предоставляет атомарное хранилище для значений любого типа. Он гарантирует, что операции записи и чтения будут выполнены безопасно при конкурентном доступе. Основное преимущество atomic.Value заключается в том, что он может хранить значения разных типов, но при этом каждое новое значение должно иметь тот же тип, что и первое сохраненное.

Синтаксис

govar v atomic.Value
v.Store(value)   // сохранение значения
val := v.Load()  // загрузка значения

Метод Store сохраняет значение в atomic.Value, а метод Load возвращает сохраненное значение. Также доступен метод Swap, который сохраняет новое значение и возвращает старое.

Пример

Давайте создадим atomic.Value для хранения строки и выполним атомарную запись и чтение:

gopackage main

import (
  "fmt"
  "sync/atomic"
)

func main() {
  var v atomic.Value
  
  // сохраняем строку
  v.Store("Hello, World!")
  
  // загружаем значение
  res := v.Load()
  fmt.Println(res)
}

Результат выполнения кода:

go"Hello, World!"

Пример

Теперь рассмотрим пример с конкурентным доступом. Несколько горутин будут безопасно обновлять значение с помощью atomic.Value:

gopackage main

import (
  "fmt"
  "sync"
  "sync/atomic"
)

func main() {
  var v atomic.Value
  v.Store("initial value")
  
  var wg sync.WaitGroup
  
  for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(id int) {
      defer wg.Done()
      newVal := fmt.Sprintf("value from goroutine %d", id)
      v.Store(newVal)
      fmt.Printf("Goroutine %d stored: %s\n", id, v.Load())
    }(i)
  }
  
  wg.Wait()
  fmt.Println("Final value:", v.Load())
}

Результат выполнения кода:

go"Goroutine 4 stored: value from goroutine 4"
"Goroutine 0 stored: value from goroutine 0"
"Goroutine 1 stored: value from goroutine 1"
"Goroutine 2 stored: value from goroutine 2"
"Goroutine 3 stored: value from goroutine 3"
"Final value: value from goroutine 3"

Обратите внимание, что порядок выполнения горутин может быть разным, но все операции с atomic.Value безопасны.

Пример

Попробуем сохранить в atomic.Value значение другого типа после того, как уже было сохранено значение типа int:

gopackage main

import (
  "fmt"
  "sync/atomic"
)

func main() {
  var v atomic.Value
  
  // сохраняем целое число
  v.Store(42)
  
  // пытаемся сохранить строку - будет паника
  // v.Store("string")
  
  // загружаем значение
  res := v.Load()
  fmt.Printf("Type: %T, Value: %v\n", res, res)
}

Результат выполнения кода:

go"Type: int, Value: 42"

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

Смотрите также

  • тип atomic.Bool,
    который представляет атомарное логическое значение
  • тип atomic.Int32,
    который представляет атомарное 32-битное целое число
  • тип atomic.Int64,
    который представляет атомарное 64-битное целое число
  • тип atomic.Pointer,
    который представляет атомарный указатель на значение