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

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

不同的工作組Done() 導致在上一個等待返回之前重用等待組

不同的工作組Done() 導致在上一個等待返回之前重用等待組

Go
至尊寶的傳說 2022-10-04 15:51:01
我正在測試,如果我把函數的開頭,像這樣:sync.WaitGroupdefer wg.Done()package mainimport (        "fmt"        "sync"        "time")func worker(wg *sync.WaitGroup, id int) error {    defer wg.Done() // put here cause error    fmt.Printf("Worker %v: Finished\n", id)    if true {        return nil    }    return nil}var wg sync.WaitGroup // I should put `wg` outside of this functionfunc callWorker(i int){    fmt.Println("Main: Starting worker", i)    fmt.Printf("Worker %v: Finished\n", id)    wg.Add(1)    go worker(&wg, i)    wg.Wait()}func main() {    for i := 0; i < 1000; i++ {        go callWorker(i)    }    time.Sleep(time.Second * 60)    fmt.Println("Main: Waiting for workers to finish")    fmt.Println("Main: Completed")}在某些情況下,我會得到,像這樣WaitGroup is reused before previous Wait has returned但是如果我把函數的末尾放進去,它就能成功運行,為什么呢?defer wg.Done()func worker(wg *sync.WaitGroup, id int) error {        fmt.Printf("Worker %v: Finished\n", id)    if true {        return nil    }    defer wg.Done() // put here, it is ok    return nil}
查看完整描述

2 回答

?
智慧大石

TA貢獻1946條經驗 獲得超3個贊

文檔指出,“如果重用 a 來等待多組獨立的事件,則必須在所有以前的 Wait 調用返回后進行新的 Add 調用”WaitGroup


在呼叫其他 goroutine 之前,您正在呼叫某些 goroutine,這是不允許的,如文檔所述。在你開始所有這些戈魯廷之前,你需要打電話,你還不如叫一次,wg.Done()wg.Add(1)wg.Addwg.Add(1000)


你的其他代碼工作的原因是它從不調用,你有wg.Done()


if true {

     return nil

}

defer wg.Done()

因此,您始終返回而不到達 defer 語句,因此永遠不會對 進行任何調用。wg.Done()


請執行下列操作:


func callWorker(i int){

    fmt.Println("Main: Starting worker", i)

    // you cannot call Add here because Done has been called in other goroutines

    go worker(&wg, i)

    wg.Wait()

}


func main() {

    wg.Add(1000) // <---- You must call Add before Done is called in any goroutine

    for i := 0; i < 1000; i++ {

        go callWorker(i)

    }

    time.Sleep(time.Second * 60)

    fmt.Println("Main: Completed")

}


查看完整回答
反對 回復 2022-10-04
?
12345678_0001

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

問題是,如果在等待組上調用,則不允許重用此等待組并再次調用它,直到返回調用(請參閱文檔)。在此程序中,調用工作函數本身就是一個 go 例程,所有調用工作函數都同時運行。在沒有等待對方的情況下,他們試圖在上一個電話未完成時打電話。Wait()Add()Wait()Add()Wait()


第一個工作線程生成結果時沒有錯誤,因為他們的調用在下一個調用(一個經典的競爭條件)之前幸運地返回。Wait()Add()


如果您希望工作線程同時運行,則必須移動并退出調用工作器函數。 必須在 for 循環之后調用。并且應該在調用工作之前在循環內調用,否則程序將在callWorker有機會向等待組添加某些內容之前完成,因此無需等待。不需要時間。睡在里面,太。Wait()Add()Wait()Add()Wait()main()


func main() {

    for i := 0; i < 1000; i++ {

        wg.Add(1)

        go callWorker(i)

    }

    wg.Wait()

    fmt.Println("Main: Waiting for workers to finish")


    fmt.Println("Main: Completed")

}


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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