атомарные счетчики

This commit is contained in:
badkaktus 2019-10-08 16:42:41 +03:00
parent acb7585e84
commit f627d67e1a
3 changed files with 29 additions and 31 deletions

View File

@ -34,7 +34,7 @@ Select
Пулы воркеров (Worker Pools)
WaitGroups
Ограничение скорости (Rate Limiting)
Atomic Counters
Атомарные счетчики (Atomic Counters)
Mutexes
Stateful Goroutines
Sorting

View File

@ -1,9 +1,8 @@
// The primary mechanism for managing state in Go is
// communication over channels. We saw this for example
// with [worker pools](worker-pools). There are a few other
// options for managing state though. Here we'll
// look at using the `sync/atomic` package for _atomic
// counters_ accessed by multiple goroutines.
// Основным механизмом управления состоянием в Go является
// связь по каналам. Мы видели это, например, с [пулами воркеров](worker-pools).
// Есть несколько других вариантов управления состоянием.
// Здесь мы рассмотрим использование пакета `sync/atomic`
// для _атомарных счетчиков_, к которым обращаются горутины.
package main
@ -15,38 +14,37 @@ import (
func main() {
// We'll use an unsigned integer to represent our
// (always-positive) counter.
// Мы будем использовать целое число без знака
// для представления нашего (всегда положительного)
// счетчика.
var ops uint64
// A WaitGroup will help us wait for all goroutines
// to finish their work.
// WaitGroup поможет нам подождать, пока все горутины
// завершат свою работу.
var wg sync.WaitGroup
// We'll start 50 goroutines that each increment the
// counter exactly 1000 times.
// Мы запустим 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 `AddUint64`, giving it the memory
// address of our `ops` counter with the
// `&` syntax.
// Для атомарного увеличения счетчика мы
// используем AddUint64, присваивая ему адрес
// памяти нашего счетчика `ops` с префиксом `&`.
atomic.AddUint64(&ops, 1)
}
wg.Done()
}()
}
// Wait until all the goroutines are done.
// Ждем пока завершатся горутины.
wg.Wait()
// It's safe to access `ops` now because we know
// no other goroutine is writing to it. Reading
// atomics safely while they are being updated is
// also possible, using functions like
// `atomic.LoadUint64`.
// Теперь доступ к `ops` безопасен, потому что мы знаем,
// что никакие другие горутины не пишут в него. Безопасное
// чтение атомарного счетчика во время его обновления также
// возможно, используя функцию `atomic.LoadUint64`.
fmt.Println("ops:", ops)
}

View File

@ -1,11 +1,11 @@
# We expect to get exactly 50,000 operations. Had we
# used the non-atomic `ops++` to increment the counter,
# we'd likely get a different number, changing between
# runs, because the goroutines would interfere with
# each other. Moreover, we'd get data race failures
# when running with the `-race` flag.
# Мы ожидаем получить ровно 50 000 операций. Если бы
# мы использовали неатомарный `ops++` для увеличения
# счетчика, мы бы, вероятно, получили другое число,
# изменяющееся между прогонами, потому что горутины
# мешали бы друг другу. Более того, мы получим сбои
# в гонке данных при работе с флагом -race.
$ go run atomic-counters.go
ops: 50000
# Next we'll look at mutexes, another tool for managing
# state.
# Далее мы рассмотрим мьютексы, еще один способ
# управления состоянием.