Введение
В этом практическом занятии мы сосредоточимся на управлении состоянием в Go с использованием пакета sync/atomic
для атомарных счётчиков, доступных нескольким goroutine.
This tutorial is from open-source community. Access the source code
💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал
В этом практическом занятии мы сосредоточимся на управлении состоянием в Go с использованием пакета sync/atomic
для атомарных счётчиков, доступных нескольким goroutine.
Задача заключается в том, чтобы увеличить счётчик ровно 1000 раз с использованием 50 goroutine и пакета sync/atomic
.
sync/atomic
для увеличения счётчика.## Мы ожидаем получить ровно 50 000 операций. Если бы мы
## использовали неатомарный `ops++` для увеличения счётчика,
## вероятно, мы бы получили другое число, меняющееся между
## запусками, потому что goroutine будут взаимодействовать
## друг с другом. Кроме того, мы бы получили ошибки о дата-расе
## при запуске с флагом `-race`.
$ go run atomic-counters.go
ops: 50000
## Далее мы рассмотрим мьютексы, другой инструмент для управления
## состоянием.
Ниже представлен полный код:
// Основной механизм управления состоянием в Go - это
// коммуникация через каналы. Мы видели это, например,
// в [пулах рабочих потоков](worker-pools). Однако есть и
// несколько других вариантов управления состоянием. Здесь мы
// рассмотрим использование пакета `sync/atomic` для
// _атомарных счётчиков_, доступных нескольким goroutine.
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
// Мы будем использовать незнаковое целое число для
// представления нашего (всегда положительного) счётчика.
var ops uint64
// WaitGroup поможет нам дождаться завершения работы всех
// goroutine.
var wg sync.WaitGroup
// Мы запустим 50 goroutine, каждая из которых увеличит
// счётчик ровно 1000 раз.
for i := 0; i < 50; i++ {
wg.Add(1)
go func() {
for c := 0; c < 1000; c++ {
// Чтобы атомарно увеличить счётчик, мы
// используем `AddUint64`, передав ему адрес
// памяти нашего счётчика `ops` с использованием
// синтаксиса `&`.
atomic.AddUint64(&ops, 1)
}
wg.Done()
}()
}
// Дождитесь завершения всех goroutine.
wg.Wait()
// Теперь безопасно получить доступ к `ops`, потому что мы
// знаем, что никакая другая goroutine не пишет в него.
// Безопасное чтение атомарных переменных во время их
// обновления также возможно с использованием функций
// типа `atomic.LoadUint64`.
fmt.Println("ops:", ops)
}
В этом практическом занятии мы узнали, как использовать пакет sync/atomic
для управления состоянием в Go путём увеличения счётчика с использованием нескольких goroutine. Функция AddUint64
использовалась для атомарного увеличения счётчика, а WaitGroup для ожидания завершения работы всех goroutine.