亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

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

在 for 范圍內使用 goroutine 運行 for range

在 for 范圍內使用 goroutine 運行 for range

Go
MYYA 2023-07-04 16:53:28
我在循環中有一個 goroutine,我想同時為 ms.Entries 中的每個項目執行一個 goroutine,但它只針對循環中的最后一個項目運行。我從一個更大的程序中抽象出了我的示例...... https://play.golang.org/p/whUMQ3pjq81package mainimport (    "fmt"    "sync")type MyStruct struct {    Entry   *Entry    Entries *[]Entry}type Entry struct {    ID   int    Name string}type Fn struct {    Res string    Err error}func main() {    e1 := Entry{ID: 1, Name: "First"}    e2 := Entry{ID: 2, Name: "Second"}    ms := &MyStruct{        Entries: &[]Entry{e1, e2},    }    fmt.Printf("MS: %+v\n", ms)    var wg sync.WaitGroup    fnChan := make(chan *Fn)    go func() {        wg.Wait()        close(fnChan)    }()    var fns []func() (string, error)    fns = append(fns, ms.actionA)    fns = append(fns, ms.actionB)    for i, entry := range *ms.Entries {        fmt.Printf("%d: %+v\n", i, entry)        ms.Entry = &entry        for j, fn := range fns {            fmt.Printf("fn loop %d\n", j)            wg.Add(1)            go ms.process(&wg, fn, fnChan)        }    }    for d := range fnChan {        fmt.Printf("fnchan: %+v\n", d)    }}func (m *MyStruct) actionA() (string, error) {    fmt.Println("actionA")    fmt.Printf("Entry: %s\n", m.Entry.Name)    return "actionA done", nil}func (m *MyStruct) actionB() (string, error) {    fmt.Println("actionB")    fmt.Printf("Entry: %s\n", m.Entry.Name)    return "actionB done", nil}func (m *MyStruct) process(wg *sync.WaitGroup, fn func() (string, error), fnChan chan<- *Fn) {    fmt.Println("processing")    var err error    defer wg.Done()    res, err := fn()    if err != nil {        fnChan <- &Fn{Err: err}        return    }    fnChan <- &Fn{Res: res}}
查看完整描述

2 回答

?
慕虎7371278

TA貢獻1802條經驗 獲得超4個贊

你已經陷入了這個陷阱:在循環迭代器變量上使用 goroutine


解決這個問題的一種方法是:

    for j, fn := range fns {

        fmt.Printf("fn loop %d\n", j)

        wg.Add(1)


        // copy the iterator variable to a local variable :

        // variables declared within the body of a loop are not shared between iterations

        f := fn

        go ms.process(&wg, f, fnChan)

    }


查看完整回答
反對 回復 2023-07-04
?
繁星coding

TA貢獻1797條經驗 獲得超4個贊

問題


你這里有一個問題:


ms.Entry = &entry

當你使用循環時,像這樣:


for i, entry := range *ms.Entries {

變量“entry”僅聲明一次。


因此&entry將有一個常數值(每次迭代中的值相同)。


但即使您解決了這個問題,另一個問題是您ms在每次迭代中都使用相同的對象。


因此,當您啟動不同的 goroutine 時,ms.Entry = ...您在第二次迭代中執行的語句將修改共享ms對象。


您還fn按照其他答案中的描述在迭代之間“共享”變量,因此您還應該捕獲該變量。


使固定


我建議您從結構中刪除該Entry字段(您不需要它,因為您已經擁有完整的數組),并使用數組位置來引用當前條目。


i int您應該向“action”和“process”函數添加一個參數。


您還需要“捕獲”fn變量。


for i, entry := range *ms.Entries {

    ...

    for j, fn := range fns {

        ...

        fn := fn // capture the fn variable

        go ms.process(&wg, fn, fnChan, i) // sending index here

    }

}

請參閱此處修改后的游樂場:


https://play.golang.org/p/uuw7r4kGBPb


查看完整回答
反對 回復 2023-07-04
  • 2 回答
  • 0 關注
  • 184 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號