簡體   English   中英

為什么這個 goroutine 不調用 wg.Done()?

[英]Why does this goroutine not call wg.Done()?

假設任何時候 registerChan 上最多有兩個元素(工作地址)。 然后由於某種原因,以下代碼在最后兩個 goroutine 中沒有調用 wg.Done()。

func schedule(jobName string, mapFiles []string, nReduce int, phase jobPhase, registerChan chan string) {
    var ntasks int
    var nOther int // number of inputs (for reduce) or outputs (for map)
    switch phase {
    case mapPhase:
        ntasks = len(mapFiles)
        nOther = nReduce
    case reducePhase:
        ntasks = nReduce
        nOther = len(mapFiles)
    }

    fmt.Printf("Schedule: %v %v tasks (%d I/Os)\n", ntasks, phase, nOther)

    const rpcname = "Worker.DoTask"
    var wg sync.WaitGroup
    for taskNumber := 0; taskNumber < ntasks; taskNumber++ {
        file := mapFiles[taskNumber%len(mapFiles)]
        taskArgs := DoTaskArgs{jobName, file, phase, taskNumber, nOther}
        wg.Add(1)
        go func(taskArgs DoTaskArgs) {
            workerAddr := <-registerChan
            print("hello\n")
            // _ = call(workerAddr, rpcname, taskArgs, nil)
            registerChan <- workerAddr
            wg.Done()
        }(taskArgs)
    }
    wg.Wait()
    fmt.Printf("Schedule: %v done\n", phase)
}

如果我將wg.Done()放在registerChan <- workerAddr之前,它工作得很好,我不知道為什么。 我也嘗試過推遲 wg.Done() ,但即使我期望它似乎也不起作用。 我想我對 go 例程和通道的工作方式有一些誤解,這導致了我的困惑。

因為它在這里:

workerAddr := <-registerChan

對於緩沖通道:
要讓這個workerAddr:= <-registerChan工作:通道registerChan必須有一個值; 否則,代碼將在此處停止等待通道


我設法以這種方式運行您的代碼(試試這個):

package main

import (
    "fmt"
    "sync"
)

func main() {
    registerChan := make(chan int, 1)
    for i := 1; i <= 10; i++ {
        wg.Add(1)
        go fn(i, registerChan)
    }
    registerChan <- 0 // seed
    wg.Wait()
    fmt.Println(<-registerChan)
}

func fn(taskArgs int, registerChan chan int) {
    workerAddr := <-registerChan
    workerAddr += taskArgs
    registerChan <- workerAddr
    wg.Done()
}

var wg sync.WaitGroup

Output:

55

解釋:
這段代碼使用一個通道和 10 個 goroutine 加上一個主 goroutine 將 1 加到 10。

我希望這有幫助。

當您運行此語句registerChan <- workerAddr時,如果通道容量已滿,您將無法添加它並且它將阻塞。 如果您有一個池,例如 10 個 workerAddr,您可以在調用schedule之前將它們全部添加到容量為 10 的緩沖通道中。 調用后不要添加,以保證如果從通道中取值,之后有空間再次添加。 在你的 goroutine 的開頭使用defer是好的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM