53 lines
1.2 KiB
Go
53 lines
1.2 KiB
Go
// The primary mechanism for managing state in Go is
|
|
// communication over channels. We saw this for example
|
|
// with [worker pools](worker-pools). There are a few other
|
|
// options for managing state though. Here we'll
|
|
// look at using the `sync/atomic` package for _atomic
|
|
// counters_ accessed by multiple goroutines.
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"sync/atomic"
|
|
)
|
|
|
|
func main() {
|
|
|
|
// We'll use an unsigned integer to represent our
|
|
// (always-positive) counter.
|
|
var ops uint64
|
|
|
|
// A WaitGroup will help us wait for all goroutines
|
|
// to finish their work.
|
|
var wg sync.WaitGroup
|
|
|
|
// We'll start 50 goroutines that each increment the
|
|
// counter exactly 1000 times.
|
|
for i := 0; i < 50; i++ {
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
for c := 0; c < 1000; c++ {
|
|
// To atomically increment the counter we
|
|
// use `AddUint64`, giving it the memory
|
|
// address of our `ops` counter with the
|
|
// `&` syntax.
|
|
atomic.AddUint64(&ops, 1)
|
|
}
|
|
wg.Done()
|
|
}()
|
|
}
|
|
|
|
// Wait until all the goroutines are done.
|
|
wg.Wait()
|
|
|
|
// It's safe to access `ops` now because we know
|
|
// no other goroutine is writing to it. Reading
|
|
// atomics safely while they are being updated is
|
|
// also possible, using functions like
|
|
// `atomic.LoadUint64`.
|
|
fmt.Println("ops:", ops)
|
|
}
|