From d38ed2a9f224dbc79adbed4fe49fe2aef137bf5b Mon Sep 17 00:00:00 2001
From: Rob Pike Serve
to
gate the creation of the goroutines.
+Here's an obvious solution, but beware it has a bug we'll fix subsequently:
func Serve(queue chan *Request) { for req := range queue { <-sem + go func() { + process(req) // Buggy; see explanation below. + sem <- 1 + }() + } +}+ +
+The bug is that in a Go for
loop, the loop variable
+is reused for each iteration, so the req
+variable is shared across all goroutines.
+That's not what we want.
+We need to make sure that req
is unique for each goroutine.
+Here's one way to do that, passing the value of req
as an argument
+to the closure in the goroutine:
+
+func Serve(queue chan *Request) { + for req := range queue { + <-sem + go func(req *Request) { + process(req) + sem <- 1 + }(req) + } +}+ +
+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: +
+ ++func Serve(queue chan *Request) { + for req := range queue { + <-sem + req := req // Create new instance of req for the goroutine. go func() { process(req) sem <- 1 @@ -2995,7 +3036,22 @@ func Serve(queue chan *Request) { }
-Another solution that manages resources well is to start a fixed +It may seem odd to write +
+ ++req := req ++ +
+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. +
+ +
+Going back to the general problem of writing the server,
+another approach that manages resources well is to start a fixed
number of handle
goroutines all reading from the request
channel.
The number of goroutines limits the number of simultaneous
--
2.50.0