Il meccanismo principale per gestire lo stato in Go
è quello di utilizzare i channel. Abbiamo visto
questo meccanismo in azione nell’esempio dei
worker pool. Ci sono una serie di altri
meccanismi per gestire lo stato. Adesso vedremo
come si possa utilizzare il package |
|
package main
|
|
import "fmt"
import "time"
import "sync/atomic"
import "runtime"
|
|
func main() {
|
|
Utilizzermo un unsigned integer per rappresentare il nostro contatore (che non sarà mai negativo). |
var ops uint64 = 0
|
Per simulare degli aggiornamenti concorrenti, avvieremo 50 goroutine. Queste goroutine incrementeranno il contatore circa ogni millisecondo. |
for i := 0; i < 50; i++ {
go func() {
for {
|
Per incrementare in modo atomico il
contatore utilizziamo la funzione |
atomic.AddUint64(&ops, 1)
|
Permettiamo alle altre goroutine di procedere. |
runtime.Gosched()
}
}()
}
|
Attendiamo un secondo per permettere alle goroutine di effettuare qualche incremento. |
time.Sleep(time.Second)
|
Al fine di poter leggere il contatore in modo sicuro,
mentre viene ancora aggiornato dalle goroutine, possiamo
estrarne una copia del valore e salvarlo dentro
|
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
}
|
Se si esegue il sorgente si vede che sono state eseguite circa 40.000 operazioni. |
$ go run atomic-counters.go
ops: 40200
|
Adesso vedremo le mutex, un altro strumento per modificare lo stato. |
Prossimo esempio: Mutex.