2 回答

TA貢獻1744條經(jīng)驗 獲得超4個贊
閉包作為 goroutine 運行會發(fā)生什么?
在并發(fā)使用閉包時可能會出現(xiàn)一些混淆。考慮以下程序:
func main() {
done := make(chan bool)
values := []string{"a", "b", "c"}
for _, v := range values {
go func() {
fmt.Println(v)
done <- true
}()
}
// wait for all goroutines to complete before exiting
for _ = range values {
<-done
}
}
人們可能會錯誤地期望看到 a、b、c 作為輸出。你可能會看到的是 c、c、c。這是因為循環(huán)的每次迭代都使用變量 v 的相同實例,因此每個閉包共享該單個變量。當(dāng)閉包運行時,它會打印 fmt.Println 執(zhí)行時 v 的值,但 v 可能在 goroutine 啟動后被修改。為了幫助在這些問題和其他問題發(fā)生之前檢測它們,請運行 go vet。
要在啟動時將 v 的當(dāng)前值綁定到每個閉包,必須修改內(nèi)部循環(huán)以在每次迭代時創(chuàng)建一個新變量。一種方法是將變量作為參數(shù)傳遞給閉包:
for _, v := range values {
go func(u string) {
fmt.Println(u)
done <- true
}(v)
}
在這個例子中,v 的值作為參數(shù)傳遞給匿名函數(shù)。然后可以在函數(shù)內(nèi)部訪問該值作為變量 u。
更簡單的方法是創(chuàng)建一個新變量,使用看起來很奇怪但在 Go 中工作正常的聲明樣式:
for _, v := range values {
v := v // create a new 'v'.
go func() {
fmt.Println(v)
done <- true
}()
}
因此,在您的情況下,通過添加語句創(chuàng)建一個新變量j := j,
for j := 0; j < MAX_TH; j++ {
j := j
go func() { getWebPageContent("http://www.example.com", messages, j) }()
}
例如,
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)
for j := 0; j < MAX_TH; j++ {
j := j
go func() { getWebPageContent("http://www.example.com", messages, j) }()
}
routine_count := 0
var page_number int
for {
page_number = <-messages
routine_count++
fmt.Println("Page number: ", page_number)
if routine_count == MAX_TH {
break
}
}
close(messages)
}
輸出:
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

TA貢獻1803條經(jīng)驗 獲得超6個贊
我的第一個 golang 回復(fù),可能完全關(guān)閉 :-)
循環(huán)可能如下所示:
...
for j := 0; j < MAX_TH; j++ {
go func(x) { getWebPageContent("http://www.example.com", messages, x) }(j)
}
...
基本上,您定義一個匿名函數(shù)并使用參數(shù)調(diào)用它。你可以用不同的方式來做,但這個解決方案看起來非常實用和時尚:-)
- 2 回答
- 0 關(guān)注
- 216 瀏覽
添加回答
舉報