Главният начин за управление на състояние на данни в Го
е чрез предаване на данни по канали. Видяхме как става
това като разгледахме работилниците.
Има и някои други възможности за управление на
състоянието. Сега ще разгледаме употребата на пакета
sync/atomic осъществяващ т. нар. неделими
броячи1, като данни, предназначени за
споделен достъп от множество съперничещи си гозадачи.
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
Ще използваме променлива стойност от вид неделимо цяло положително число, за нашия (винаги положителен) брояч.
var действия atomic.Uint64
Ще си направим чакалня с WaitGroup, за да
изчакаме всички задачи да приключат.
var wg sync.WaitGroup
Ще пуснем 50 гозадачи, всяка от които ще увеличи стойността на брояча точно 1000 пъти.
for range 50 {
wg.Go(func() {
for range 1000 {
За да увеличим стойността на брояча
чрез неделимо действие, ползваме метода
Add.
действия.Add(1)
}
})
}
Чакаме всички гозадачки да приключат.
wg.Wait()
Тук вече никоя гозадаче не пише в действия, но благодарения на метода Load знаем, че действието зареждане (load) е неделимо, дори ако други задачи обновяваха стойността в действия.
fmt.Println("действия:", действия.Load())
}
Очакваме програмата ни да изведе на екрана точно 50000 –
броят извършени действия – увеличаване с единица. Ако
бяхме използвали обикновено – не неделимо число, щяхме
да видим друго число, което щеше даже да е различно при
всяко пускане на програмата Причината щеше да се състои
в това, че няколко гозадачи щяха да виждат една и съща
стойност на числото едновременно. Също щяхме да получим
и предупреждения за „съревнование“ (race), ако пуснехме
програмата с флаг -race.
$ go run atomic-counters.go
действия: 50000
В следващия пример ще разгледаме взаимното изключване – друг способ за управление на състояние.
Следващ пример: Взаимно изключване.