第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Goroutine 使用通道奇怪的結(jié)果

Goroutine 使用通道奇怪的結(jié)果

Go
開滿天機 2021-12-07 19:33:20
當(dāng)我運行 goroutines 時,我通常得到 40 作為值,我知道它的并發(fā)性,但為什么最后一個數(shù)字來了?我想輸出必須是:Page number:  34  Page number:  12  Page number:  8  Page number:  2  Page number:  29示例源代碼:package mainimport (    "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 = 40func main() {    // pln := fmt.Println    messages := make(chan int)    for j := 0; j < MAX_TH; 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)}
查看完整描述

2 回答

?
慕無忌1623718

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


查看完整回答
反對 回復(fù) 2021-12-07
?
慕碼人8056858

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)用它。你可以用不同的方式來做,但這個解決方案看起來非常實用和時尚:-)


查看完整回答
反對 回復(fù) 2021-12-07
  • 2 回答
  • 0 關(guān)注
  • 216 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號