91 lines
2.3 KiB
Go
91 lines
2.3 KiB
Go
// built-in synchronization features of goroutines and channels
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
// state will be owned by a single goroutine
|
|
// this will guarantee that the data is never corrupted with concurrent access
|
|
// in order to read or write that state, other goroutines will send messages to the owning goroutine and receive corresponding replies
|
|
// these readOp and writeOp structs encapsulate those requests and a way for the owning goroutine to respond
|
|
type readOp struct {
|
|
key int
|
|
resp chan int
|
|
}
|
|
type writeOp struct {
|
|
key int
|
|
val int
|
|
resp chan bool
|
|
}
|
|
|
|
func main() {
|
|
// count how many operations to perform
|
|
var readOps uint64
|
|
var writeOps uint64
|
|
|
|
// reads and writes channels will be used by other goroutines
|
|
reads := make(chan readOp)
|
|
writes := make(chan writeOp)
|
|
|
|
// goroutine that owns the state, which is a map as in the previous example but now private to the stateful goroutine
|
|
// this goroutine repeatedly selects on the reads and writes channels, responding to requests as they arrive
|
|
go func() {
|
|
var state = make(map[int]int)
|
|
for {
|
|
select {
|
|
case read := <-reads:
|
|
read.resp <- state[read.key]
|
|
case write := <-writes:
|
|
state[write.key] = write.val
|
|
write.resp <- true
|
|
}
|
|
}
|
|
}()
|
|
|
|
// starts 100 goroutines to issue reads to the state-owning goroutine via the reads channel
|
|
for r := 0; r < 100; r++ {
|
|
go func() {
|
|
for {
|
|
// each read requires constructing a readOp, sending it over the reads channel, and the receiving the result over the provided resp channel
|
|
read := readOp{
|
|
key: rand.Intn(5),
|
|
resp: make(chan int)}
|
|
reads <- read
|
|
<-read.resp
|
|
atomic.AddUint64(&readOps, 1)
|
|
time.Sleep(time.Millisecond)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// start 10 writes as well, using a similar approach
|
|
for w := 0; w < 10; w++ {
|
|
go func() {
|
|
for {
|
|
write := writeOp{
|
|
key: rand.Intn(5),
|
|
val: rand.Intn(100),
|
|
resp: make(chan bool)}
|
|
writes <- write
|
|
<-write.resp
|
|
atomic.AddUint64(&writeOps, 1)
|
|
time.Sleep(time.Millisecond)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// let the goroutines work for a second
|
|
time.Sleep(time.Second)
|
|
|
|
// capture and report the op counts
|
|
readOpsFinal := atomic.LoadUint64(&readOps)
|
|
fmt.Println("readOps:", readOpsFinal)
|
|
writeOpsFinal := atomic.LoadUint64(&writeOps)
|
|
fmt.Println("writeOps:", writeOpsFinal)
|
|
}
|