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.52.0