Compteurs atomiques
#
// Le mécanisme principal pour gérer les états en Go,
// c'est la communication à travers les canaux. Nous
// avons vu ceci par exemple avec les [worker pools](worker-pools).
// Il y a quelques autres options pour gérer les états
// ceci dit. Ici, nous allons utiliser le package
// `sync/atomic` pour des _compteurs atomiques_ auxquels
// accèdent plusieurs goroutines.
package main
import "fmt"
import "time"
import "sync/atomic"
import "runtime"
func main() {
// Nous utiliserons un entier non-signé pour
// représenter notre compteur (toujours positif).
var ops uint64 = 0
// Pour simuler des mises à jour concurrentes, nous
// commençons 50 goroutines qui incrémentent le
// compteur environ une fois par milliseconde.
for i := 0; i < 50; i++ {
go func() {
for {
// Pour incrémenter atomiquement le
// compteur, nous utilisons `AddUint64`,
// en luis donnant l'adresse mémoire de
// notre compteur `ops` avec la syntaxe
// `&`.
atomic.AddUint64(&ops, 1)
// On fait continuer la goroutine.
runtime.Gosched()
}
}()
}
// On attend une seconde pour permettre aux
// goroutines de travailler, et au compteur de
// grandir en valeur.
time.Sleep(time.Second)
// Afin d'utiliser le compteur de manière sûre alors
// qu'il est toujours mis à jour par les autres
// goroutines, on extraie une copie de la valeur
// courante dans `opsFinal` via `LoadUint64`.
// Comme plus haut, nous devons donner à cette
// fonction l'adresse mémoire `&ops` depuis laquelle
// chercher la valeur.
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
}
# Lancer le programme montre qu'environ 40,000 operations
# ont été exécutées.
$ go run atomic-counters.go
ops: 40200
# Ensuite nous regarderons les mutexes, un autre outil
# pour gérer les états.