_content/doc/effective_go: remove discussion of loop variable reuse
It's no longer needed as of the Go 1.22 release. Fixes golang/go#68808 Change-Id: Ib968a414703d28c1d4b4c5300bb5c697264b639e Reviewed-on: https://go-review.googlesource.com/c/website/+/604575 Reviewed-by: Carlos Amedee <carlos@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Reviewed-by: Rob Pike <r@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Родитель
31640b1e1a
Коммит
b81d4dff74
|
@ -2870,8 +2870,7 @@ every incoming request, even though only <code>MaxOutstanding</code>
|
|||
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:
|
||||
gate the creation of the goroutines:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
|
@ -2879,69 +2878,20 @@ func Serve(queue chan *Request) {
|
|||
for req := range queue {
|
||||
sem <- 1
|
||||
go func() {
|
||||
process(req) // Buggy; see explanation below.
|
||||
process(req)
|
||||
<-sem
|
||||
}()
|
||||
}
|
||||
}</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>
|
||||
(Note that in Go versions before 1.22 this code has a bug: the loop
|
||||
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 {
|
||||
sem <- 1
|
||||
go func(req *Request) {
|
||||
process(req)
|
||||
<-sem
|
||||
}(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 {
|
||||
req := req // Create new instance of req for the goroutine.
|
||||
sem <- 1
|
||||
go func() {
|
||||
process(req)
|
||||
<-sem
|
||||
}()
|
||||
}
|
||||
}</pre>
|
||||
|
||||
<p>
|
||||
It may seem odd to write
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
req := req
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
but it's 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.
|
||||
See the <a href="/wiki/LoopvarExperiment">Go wiki</a> for details.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Going back to the general problem of writing the server,
|
||||
another approach that manages resources well is to start a fixed
|
||||
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
|
||||
|
|
Загрузка…
Ссылка в новой задаче