Go goroutine with channel strange result -
when run goroutines, 40 value, know concurrency why last number coming? suppose output must be:
page number: 34 page number: 12 page number: 8 page number: 2 page number: 29
example source code:
package main import ( "fmt" "io/ioutil" "net/http" ) func getwebpagecontent(url string, c chan int, val int) interface{} { if r, err := http.get(url); err == nil { defer r.body.close() if body, err := ioutil.readall(r.body); err == nil { c <- val return string(body) } } else { fmt.println(err) } return "xox" } const max_th = 40 func main() { // pln := fmt.println messages := make(chan int) j := 0; j < max_th; j++ { go func() { getwebpagecontent("http://www.example.com", messages, j) }() } routine_count := 0 var page_number int { page_number = <-messages routine_count++ fmt.println("page number: ", page_number) if routine_count == max_th { break } } close(messages) }
the go programming language
frequently asked questions (faq)
what happens closures running goroutines?
some confusion may arise when using closures concurrency. consider following program:
func main() { done := make(chan bool) values := []string{"a", "b", "c"} _, v := range values { go func() { fmt.println(v) done <- true }() } // wait goroutines complete before exiting _ = range values { <-done } }
one might mistakenly expect see a, b, c output. you'll see instead c, c, c. because each iteration of loop uses same instance of variable v, each closure shares single variable. when closure runs, prints value of v @ time fmt.println executed, v may have been modified since goroutine launched. detect , other problems before happen, run go vet.
to bind current value of v each closure launched, 1 must modify inner loop create new variable each iteration. 1 way pass variable argument closure:
for _, v := range values { go func(u string) { fmt.println(u) done <- true }(v) }
in example, value of v passed argument anonymous function. value accessible inside function variable u.
even easier create new variable, using declaration style may seem odd works fine in go:
for _, v := range values { v := v // create new 'v'. go func() { fmt.println(v) done <- true }() }
therefore, in case, create new variable adding statement j := j
,
for j := 0; j < max_th; j++ { j := j go func() { getwebpagecontent("http://www.example.com", messages, j) }() }
for example,
package main import ( "fmt" "io/ioutil" "net/http" ) func getwebpagecontent(url string, c chan int, val int) interface{} { if r, err := http.get(url); err == nil { defer r.body.close() if body, err := ioutil.readall(r.body); err == nil { c <- val return string(body) } } else { fmt.println(err) } return "xox" } const max_th = 40 func main() { // pln := fmt.println messages := make(chan int) j := 0; j < max_th; j++ { j := j go func() { getwebpagecontent("http://www.example.com", messages, j) }() } routine_count := 0 var page_number int { page_number = <-messages routine_count++ fmt.println("page number: ", page_number) if routine_count == max_th { break } } close(messages) }
output:
page number: 23 page number: 6 page number: 1 page number: 3 page number: 28 page number: 32 page number: 18 page number: 22 page number: 0 page number: 36 page number: 7 page number: 21 page number: 12 page number: 2 page number: 5 page number: 4 page number: 33 page number: 13 page number: 20 page number: 27 page number: 29 page number: 8 page number: 31 page number: 10 page number: 17 page number: 25 page number: 19 page number: 35 page number: 14 page number: 38 page number: 15 page number: 30 page number: 37 page number: 39 page number: 26 page number: 9 page number: 16 page number: 11 page number: 24 page number: 34
Comments
Post a Comment