Commit d38ed2a9 authored by Rob Pike's avatar Rob Pike

doc/effective_go: fix server example that shares var between goroutines

Use it as a teaching example about how to solve this problem.

Fixes #6501

R=golang-dev, adg, rsc
CC=golang-dev
https://golang.org/cl/14250043
parent 1b0bffa9
......@@ -2981,12 +2981,53 @@ of them can run at any moment.
As a result, the program can consume unlimited resources if the requests come in too fast.
We can address that deficiency by changing <code>Serve</code> to
gate the creation of the goroutines.
Here's an obvious solution, but beware it has a bug we'll fix subsequently:
</p>
<pre>
func Serve(queue chan *Request) {
for req := range queue {
&lt;-sem
go func() {
process(req) // Buggy; see explanation below.
sem &lt;- 1
}()
}
}</pre>
<p>
The bug is that in a Go <code>for</code> loop, the loop variable
is reused for each iteration, so the <code>req</code>
variable is shared across all goroutines.
That's not what we want.
We need to make sure that <code>req</code> is unique for each goroutine.
Here's one way to do that, passing the value of <code>req</code> as an argument
to the closure in the goroutine:
</p>
<pre>
func Serve(queue chan *Request) {
for req := range queue {
&lt;-sem
go func(req *Request) {
process(req)
sem &lt;- 1
}(req)
}
}</pre>
<p>
Compare this version with the previous to see the difference in how
the closure is declared and run.
Another solution is just to create a new variable with the same
name, as in this example:
</p>
<pre>
func Serve(queue chan *Request) {
for req := range queue {
&lt;-sem
req := req // Create new instance of req for the goroutine.
go func() {
process(req)
sem &lt;- 1
......@@ -2995,7 +3036,22 @@ func Serve(queue chan *Request) {
}</pre>
<p>
Another solution that manages resources well is to start a fixed
It may seem odd to write
</p>
<pre>
req := req
</pre>
<p>
but it's a legal and idiomatic in Go to do this.
You get a fresh version of the variable with the same name, deliberately
shadowing the loop variable locally but unique to each goroutine.
</p>
<p>
Going back to the general problem of writing the server,
another approach that manages resources well is to start a fixed
number of <code>handle</code> goroutines all reading from the request
channel.
The number of goroutines limits the number of simultaneous
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment