Go中缓冲通道的死锁

Deadlocks with buffered channels in Go

我遇到以下代码fatal error: all goroutines are asleep - deadlock!

我使用缓冲通道是否正确?如果你能给我指点,我将不胜感激。不幸的是,我已经无计可施了。

func main() {
    valueChannel := make(chan int, 2)
    defer close(valueChannel)
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go doNothing(&wg, valueChannel)
    }

    for {
        v, ok := <- valueChannel
        if !ok {
            break
        }
        fmt.Println(v)
    }
    wg.Wait()
}

func doNothing(wg *sync.WaitGroup, numChan chan int) {
    defer wg.Done()
    time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
    numChan <- 12
}

主 goroutine 在收到所有值后阻塞 <- valueChannel。关闭通道以解锁主 goroutine。

func main() {
    valueChannel := make(chan int, 2)
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go doNothing(&wg, valueChannel)
    }

    // Close channel after goroutines complete.
    go func() {
        wg.Wait()
        close(valueChannel)
    }()

    // Receive values until channel is closed. 
    // The for / range loop here does the same
    // thing as the for loop in the question.
    for v := range valueChannel {
        fmt.Println(v)
    }
 }

Run the example on the playground.

上面的代码独立于 goroutines 发送的值的数量。 如果 main() 函数可以确定 goroutine 发送的值的数量,则从 main():

接收该数量的值
func main() {
    const n = 10

    valueChannel := make(chan int, 2)
    for i := 0; i < n; i++ {
        go doNothing(valueChannel)
    }

    // Each call to doNothing sends one value. Receive
    // one value for each call to doNothing.
    for i := 0; i < n; i++ {
        fmt.Println(<-valueChannel)
    }
}

func doNothing(numChan chan int) {
    time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
    numChan <- 12
}

Run the example on the playground.

主要问题出在频道接收的for循环上。 逗号 ok 习语在通道上略有不同,ok 表示接收到的值是在通道上发送的 (true) 还是因为通道关闭且为空而返回的零值 (false)。 在这种情况下,通道正在等待发送数据,因为它已经完成十次发送值:Deadlock。 因此,除了代码设计之外,如果我只需要在这里做尽可能少的更改,那就是:

func main() {
    valueChannel := make(chan int, 2)
    defer close(valueChannel)
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go doNothing(&wg, valueChannel)
    }

    for i := 0; i < 10; i++ {
        v := <- valueChannel

        fmt.Println(v)
    }
    wg.Wait()
}

func doNothing(wg *sync.WaitGroup, numChan chan int) {
    defer wg.Done()
    time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
    numChan <- 12
}