publish atomic counters
This commit is contained in:
parent
7098c32ade
commit
e7cb1d1ac8
@ -38,8 +38,9 @@ Timers
|
||||
Tickers
|
||||
Worker Pools
|
||||
Rate Limiting
|
||||
# State Goroutine
|
||||
# State Mutex
|
||||
Atomic Counters
|
||||
# Mutexs
|
||||
# Stateful Goroutines
|
||||
Sorting
|
||||
Sorting by Functions
|
||||
# Collection Functions
|
||||
|
48
examples/atomic-counters/atomic-counters.go
Normal file
48
examples/atomic-counters/atomic-counters.go
Normal file
@ -0,0 +1,48 @@
|
||||
// The primary mechanism for managing state in Go is
|
||||
// communication over channels. We saw this for example
|
||||
// with [worker pools](worker-pool). There are a few other
|
||||
// options for managing state though. Here we'll
|
||||
// look at using the `sync/atomic` package for simple
|
||||
// counters accessed by multiple goroutines.
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import "time"
|
||||
import "sync/atomic"
|
||||
|
||||
func main() {
|
||||
|
||||
// We'll use an unsigned integer to represent our
|
||||
// (always-positive) counter.
|
||||
var ops uint64 = 0
|
||||
|
||||
// To simulate concurrent updates, we'll start 50
|
||||
// goroutines that each increment the counter about
|
||||
// once a millisecond.
|
||||
for i := 0; i < 50; i++ {
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Millisecond)
|
||||
|
||||
// To atomically increment the counter we
|
||||
// use `AddUint64`, giving it the memory
|
||||
// address of our `ops` counter with the
|
||||
// `&` syntax.
|
||||
atomic.AddUint64(&ops, 1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait a second to allow some ops to accumulate.
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// In order to safely use the counter while it's still
|
||||
// being updated by other goroutines, we extract a
|
||||
// copy of the current value into `opsFinal` via
|
||||
// `LoadUint64`. As above we need to give this
|
||||
// function the memory address `&ops` from which to
|
||||
// fetch the value.
|
||||
opsFinal := atomic.LoadUint64(&ops)
|
||||
fmt.Println("ops:", opsFinal)
|
||||
}
|
4
examples/atomic-counters/atomic-counters.sh
Normal file
4
examples/atomic-counters/atomic-counters.sh
Normal file
@ -0,0 +1,4 @@
|
||||
# Running the program shows that we executed about
|
||||
# 40,000 operations.
|
||||
$ go run atomic-counters.go
|
||||
ops: 40200
|
@ -1,3 +1,5 @@
|
||||
// State
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
@ -7,14 +9,6 @@ import "sync"
|
||||
import "sync/atomic"
|
||||
import "runtime"
|
||||
|
||||
func randKey() int {
|
||||
return rand.Intn(10)
|
||||
}
|
||||
|
||||
func randVal() int {
|
||||
return rand.Intn(100)
|
||||
}
|
||||
|
||||
// Globally-accessible state.
|
||||
var data = make(map[int]int)
|
||||
|
||||
@ -27,7 +21,7 @@ var opCount int64 = 0
|
||||
func generateReads() {
|
||||
total := 0
|
||||
for {
|
||||
key := randKey()
|
||||
key := rand.Intn(10)
|
||||
dataMutex.Lock()
|
||||
total += data[key]
|
||||
dataMutex.Unlock()
|
||||
@ -39,8 +33,8 @@ func generateReads() {
|
||||
// Generate random writes.
|
||||
func generateWrites() {
|
||||
for {
|
||||
key := randKey()
|
||||
val := randVal()
|
||||
key := rand.Intn(10)
|
||||
val := rand.Intn(100)
|
||||
dataMutex.Lock()
|
||||
data[key] = val
|
||||
dataMutex.Unlock()
|
||||
@ -62,5 +56,3 @@ func main() {
|
||||
finalOpCount := atomic.LoadInt64(&opCount)
|
||||
fmt.Println(finalOpCount)
|
||||
}
|
||||
|
||||
// todo: "State with Mutexes?"
|
||||
|
Loading…
x
Reference in New Issue
Block a user