Атомарні Лічильники|Atomic Counters
#
// Як ми вже дізнались, основним механізмом роботи управлінням стану
// в Go є, канали комунікації (або комунікація каналами).
// Ми побачили це на прикладі "[пулу працівників](worker-pools)" на додадчу
// до інших випадків.
// Але існують і інші способи управління станом та асинхронністю,
// розглянемо, наприклад, пакет `sync/atomic` для
// _атомарних лічильників_, доступ до яких є у кількох горутин.
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
// Ось ми використаємо беззнакове ціле для представлення
// нашого (завжди додатнього) лічильника.
var ops atomic.Uint64
// WaitGroup допоможе нам зачекати поки усі горутини
// завершать свою роботу.
var wg sync.WaitGroup
// Для симуляції одночасних оновлень, ми запускаємо 50
// горутин, які оновлюватимуть лічильник рівно 1000 разів.
for i := 0; i < 50; i++ {
wg.Add(1)
go func() {
for c := 0; c < 1000; c++ {
// To atomically increment the counter we use `Add`.
ops.Add(1)
}
wg.Done()
}()
}
// Чекаємо поки усі горутини не відпрацюють.
wg.Wait()
// Жодна горутина не записує до 'ops', але використаємо
// `Load` для безпечного читання значення (навіть тоді коли інши
// горутини його оновлюють).
fmt.Println("ops:", ops.Load())
}
# Ми очікувано отримали рівно 50000 операцій.
# Як би ми використали не атомарний 'ops++'
# числа б - були інші. Ми доречі можемо
# отримувати дані про стан гонки даних
# коли запускаємо з прапорцем `-race`.
$ go run atomic-counters.go
ops: 50000
# Надалі ми ознайомимось з `mutexe`ами, ще одниx з
# інструментів Go - призначення якого управління станом.