This bit of the Effective Go document threw me also. In fact, in relatively recent versions of Effective Go, the code in question acquired the semaphore on a channel send (instead of a channel receive like it does in the current version, which uses the init() to "prime" the channel).
There has apparently been a good deal of discussion on the topic. I won't bother trying to summarize everything, but the discussion can all be found from here:
https://code.google.com/p/go/issues/detail?id=5023
It does strike me as unfortunate, but quoting the filer of that issue, the short story appears to be that unless the semaphore is acquired on the channel receive...:
The following code:
func handle(r *Request) {
sem <- 1 // Wait for active queue to drain.
process(r) // May take a long time.
<-sem // Done; enable next request to run.
}
...could legally be "optimized" into:
func handle(r *Request) {
process(r) // May take a long time.
sem <- 1 // Wait for active queue to drain.
<-sem // Done; enable next request to run.
}
...or into:
func handle(r *Request) {
sem <- 1 // Wait for active queue to drain.
<-sem // Done; enable next request to run.
process(r) // May take a long time.
}