forked from mmcgrana/gobyexample
/
atomic-counters.go
53 lines (45 loc) · 2.46 KB
/
atomic-counters.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Основной механизм управления состоянием в Go
// – связь через каналы. Вы видели это в примере
// с [набором обработчиков](worker-pools).
// Но есть несколько других вариантов для управления
// состоянием. В этом примере мы рассмотрим
// использование пакета `sync/atomic` для атомарных
// счетчиков, доступных нескольким горутинам.
package main
import "fmt"
import "time"
import "sync/atomic"
import "runtime"
func main() {
// Мы будем использовать беззнаковое целое
// число для представления нашего
// (всегда положительного) счетчика.
var ops uint64 = 0
// Для эмуляции конкурентных обновлений,
// мы запустим 50 горутин, которые будут
// увеличивать счетчик примерно
// каждую миллисекунду.
for i := 0; i < 50; i++ {
go func() {
for {
// Для атомарного увеличения счётчика используем
// функцию `AddUint64`, передавая ей указатель
// на адрес в памяти, где хранится `ops`,
// с использованием в синтаксисе `&`.
atomic.AddUint64(&ops, 1)
// Разрешим остальным горутинам продолжить работу.
runtime.Gosched()
}
}()
}
// Подождем секунду для накопления
// результатов работы.
time.Sleep(time.Second)
// Чтобы безопасно использовать счётчик в то время,
// пока он обновляется другими горутинами, сделаем копию
// текущего значения в `opsFinal` через `LoadUint64`.
// Как уже делалось выше, нужно передать этой функции
// адрес памяти `&ops`, из которого будет получено значение.
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
}