Concurrency in Go
Concurrency in Go
Go concurrency motto:
"Do not communicate by sharing memory; instead, share
memory by communicating"
go foo()
go func() {
logger.Printf("Hello, %s!", who)
...
}()
Channels
c := make(chan int, N)
// fork
for i := 0; i < N; i++ {
go func() {
result := ...
c <- result
}()
}
// join
sum := 0
for i := 0; i < N; i++ {
sum += <-c
}
Select
select {
case c1 <- foo:
case m := <-c2:
doSomething(m)
case m := <-c3:
doSomethingElse(m)
default:
doDefault()
}
Select: non-blocking send/recv
httpReq := parse()
select {
case reqChan <- httpReq:
default:
reply(httpReq, 503)
}
Select: timeouts
select {
case c <- foo:
case <-time.After(1e9):
}
Example: Barber Shop
var seats = make(chan Customer, 4)
func barber() {
for {
c := <-seats
// shave c
}
}
go barber()
It is that simple!
Example: Resource Pooling
It is that simple!
c := make(chan interface{})
go func() {
m := make(map[string]string)
for {
switch r := (<-c).(type) {
case ReadReq:
r.ack <- m[r.key]
case WriteReq:
m[r.key] = r.val
}
}
}()
Example: Actor-oriented programming
It is that simple!
Example: Thread Pool
obj1 := <-ack1
obj2 := <-ack2
WTF??1!
Why does pure CSP suck?
Some application code is no different!
- Additional overheads
- Additional latency
- Unnecessary complexity (asynchrony, reorderings)
- Load balancing
- Overload control
- Hard to debug
Shared Memory to the Rescue!
sync.Mutex
sync.RWMutex
sync.Cond
sync.Once
sync.WaitGroup
runtime.Semacquire/Semrelease
atomic.CompareAndSwap/Add/Load
Mutexes
sync.Mutex is actually a cooperative binary semaphore - no
ownership, no recursion.
mtx.Lock()
go func() {
...
mtx.Unlock()
}
mtx.Lock()
func foo() {
mtx.Lock()
defer mtx.Unlock()
...
}
General Scheme
90% of CSP on higher levels
+10% of Shared Memory on lower levels
Read/Pars
Accept Accept Cache Disk IO
Accept Write
e
Accept Accept Accept
Accept
CSP
Shared
Memory
Resource Quota/Licensing
Statistics Config/Settings
Polling mgmt
Race Detector for Go
"I've just run a real world benchmark provided by someone using mgo
with the r59 release, and it took about 5 seconds out of 20, without any
changes in the code."