Stateful Goroutines
Confine mutable state to a single goroutine and expose it through channels to avoid data races by design.
Instead of sharing state protected by a mutex, you can confine state to a single goroutine and expose read and write access through channels. This pattern eliminates data races by construction: only one goroutine ever touches the state.
A state goroutine owns a map. Callers send command structs over channels and receive results via per-request reply channels. The state goroutine serializes all access in its select loop.
package main
import "fmt"
type readOp struct {
key int
resp chan int
}
type writeOp struct {
key int
val int
resp chan bool
}
func main() {
reads := make(chan readOp)
writes := make(chan writeOp)
// state goroutine: sole owner of the map
go func() {
state := make(map[int]int)
for {
select {
case op := <-reads:
op.resp <- state[op.key]
case op := <-writes:
state[op.key] = op.val
op.resp <- true
}
}
}()
// write
w := writeOp{key: 1, val: 42, resp: make(chan bool)}
writes <- w
<-w.resp
// read
r := readOp{key: 1, resp: make(chan int)}
reads <- r
fmt.Println("value:", <-r.resp) // 42
}Compare the two approaches:
| Approach | Best for |
|---|---|
| Mutex | Simple read-modify-write; high-throughput counters |
| Stateful goroutine | Complex state transitions; protocol-like sequencing |
The stateful goroutine is heavier than a mutex for a plain counter but shines when state transitions follow a protocol - for example, a connection that must be in idle before it can move to in-flight:
type connState int
const (
idle connState = iota
inflight
closing
)
// transition is enforced inside the state goroutine's select,
// so callers can never put the connection into an invalid state.In production
The stateful goroutine pattern (one goroutine owns mutable state, all access goes through a channel) avoids data races by design. It trades throughput for correctness guarantees. Use it when the state transitions are complex or when you want to model a protocol; use a mutex when the critical section is a simple read-modify-write.
Enjoyed this? Get more essays on software craft delivered to your inbox.
Subscribe free