Тип atomic.Int64

Тип atomic.Int64 представляет 64-битное целое число, с которым можно безопасно работать из разных горутин без использования мьютексов. Этот тип предоставляет методы для атомарного чтения, записи, сложения и сравнения значений. Данный тип находится в пакете sync/atomic и является рекомендуемой альтернативой функциям вида atomic.LoadInt64 и atomic.StoreInt64, так как предоставляет более удобный и типобезопасный интерфейс.

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

Синтаксис

Для использования типа atomic.Int64 необходимо импортировать пакет sync/atomic. Создается переменная типа atomic.Int64, после чего можно вызывать ее методы.

govar counter atomic.Int64
counter.Add(10)
val := counter.Load()

Метод Add - атомарное сложение

Метод Add прибавляет переданное значение к текущему значению atomic.Int64 и возвращает новое значение. Этот метод работает атомарно и эквивалентен операции atomic.AddInt64.

gopackage main

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

func main() {
  var counter atomic.Int64
  var wg sync.WaitGroup

  for i := 0; i < 100; i++ {
    wg.Add(1)
    go func() {
      defer wg.Done()
      newVal := counter.Add(1)
      fmt.Printf("New value: %d\n", newVal)
    }()
  }

  wg.Wait()
  fmt.Printf("Final counter: %d\n", counter.Load())
}

Результат выполнения кода (порядок чисел может меняться):

go"New value: 1"
"New value: 2"
...
"New value: 100"
"Final counter: 100"

Метод Load - атомарное чтение

Метод Load атомарно возвращает текущее значение atomic.Int64. Он гарантирует, что чтение будет выполнено целостно, без промежуточных состояний, и эквивалентен функции atomic.LoadInt64.

gopackage main

import (
  "fmt"
  "sync/atomic"
)

func main() {
  var value atomic.Int64
  value.Store(42)

  res := value.Load()
  fmt.Printf("Loaded value: %d\n", res)
}

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

go"Loaded value: 42"

Метод Store - атомарная запись

Метод Store атомарно устанавливает новое значение для atomic.Int64. Эта операция эквивалентна функции atomic.StoreInt64 и гарантирует, что запись будет выполнена атомарно, без промежуточных состояний.

gopackage main

import (
  "fmt"
  "sync/atomic"
)

func main() {
  var value atomic.Int64
  value.Store(100)

  fmt.Printf("Stored value: %d\n", value.Load())
}

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

go"Stored value: 100"

Метод Swap - атомарная замена

Метод Swap атомарно устанавливает новое значение и возвращает предыдущее. Эта операция эквивалентна функции atomic.SwapInt64 и полезна, когда нужно получить старое значение в момент замены.

gopackage main

import (
  "fmt"
  "sync/atomic"
)

func main() {
  var value atomic.Int64
  value.Store(10)

  old := value.Swap(20)
  fmt.Printf("Old value: %d, New value: %d\n", old, value.Load())
}

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

go"Old value: 10, New value: 20"

Метод CompareAndSwap - атомарное сравнение с заменой

Метод CompareAndSwap сравнивает текущее значение с ожидаемым и, если они равны, устанавливает новое значение. Операция возвращает true, если замена произошла. Этот метод эквивалентен функции atomic.CompareAndSwapInt64 и является основой для реализации lock-free алгоритмов.

gopackage main

import (
  "fmt"
  "sync/atomic"
)

func main() {
  var value atomic.Int64
  value.Store(5)

  swapped := value.CompareAndSwap(5, 10)
  fmt.Printf("Swapped: %t, Value: %d\n", swapped, value.Load())

  swapped = value.CompareAndSwap(5, 20)
  fmt.Printf("Swapped: %t, Value: %d\n", swapped, value.Load())
}

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

go"Swapped: true, Value: 10"
"Swapped: false, Value: 10"

Пример использования в счетчике

Рассмотрим практический пример использования atomic.Int64 для создания потокобезопасного счетчика, который инкрементируется из нескольких горутин:

gopackage main

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

type Counter struct {
  value atomic.Int64
}

func (c *Counter) Inc() int64 {
  return c.value.Add(1)
}

func (c *Counter) Get() int64 {
  return c.value.Load()
}

func main() {
  counter := &Counter{}
  var wg sync.WaitGroup

  for i := 0; i < 50; i++ {
    wg.Add(1)
    go func() {
      defer wg.Done()
      for j := 0; j < 10; j++ {
        counter.Inc()
      }
    }()
  }

  wg.Wait()
  fmt.Printf("Total count: %d\n", counter.Get())
}

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

go"Total count: 500"

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

  • тип atomic.Int32,
    предоставляющий атомарные операции для 32-битных целых чисел
  • тип atomic.Uint64,
    предоставляющий атомарные операции для беззнаковых 64-битных целых чисел
  • функцию atomic.AddInt64,
    которая атомарно прибавляет значение к int64
  • тип atomic.Bool,
    предоставляющий атомарные операции для булевых значений