waitgroup.Wait() 造成死锁

waitgroup.Wait() causing dead lock

我想弄清楚为什么 waitgroup.Wait()

会出现死锁
package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func foo(c chan int, i int) {
    defer wg.Done()
    c <- i
}

func main() {
    ch := make(chan int)
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go foo(ch, i)
    }
    wg.Wait()
    close(ch)
    for item := range ch {
        fmt.Println(item)
    }
}

当我运行这样时,它会打印fatal error: all goroutines are asleep - deadlock!

我尝试将 ch 更改为缓冲频道,这解决了问题。但是我很想知道为什么会出现死锁。

我已经把你程序逻辑不正确的部分注释掉了:

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func foo(c chan int, i int) {
    defer wg.Done()
    c <- i
}

func main() {
    ch := make(chan int) // unbuffered channel

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go foo(ch, i)
    }

    // wg.Wait is waiting for all goroutines to finish but that's
    // only possible if the send to channel succeeds. In this case,
    // it is not possible as your receiver "for item := range ch" is below
    // this. Hence, a deadlock.
    wg.Wait()

    // Ideally, it should be the sender's duty to close the channel.
    // And closing a channel before the receiver where the channel
    // is unbuffered is not correct.
    close(ch)

    for item := range ch {
        fmt.Println(item)
    }
}

更正的程序:

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func foo(c chan int, i int) {
    defer wg.Done()
    c <- i
}

func main() {
    ch := make(chan int)

    go func() {
        for item := range ch {
            fmt.Println(item)
        }
    }()

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go foo(ch, i)
    }

    wg.Wait()
    close(ch)
}