Contatori Atomici

Contatori Atomici #

// 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](worker-pools). Ci sono una serie di altri
// meccanismi per gestire lo stato. Adesso vedremo
// come si possa utilizzare il package `sync/atomic`
// per realizzare un _contatore atomico_ che viene
// letto e aggiornato da svariate goroutine.

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 `AddUint64`
                // passandogli il puntatore alla variabile `ops`
                // utilizzando l'operatore `&`.
                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` tramite la funzione `LoadUint64`.
    // Come sopra, dobbiamo passare a questa funzione
    // il puntatore `&ops` dal quale leggere il valore
    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.