我不明白为什么这适用于无缓冲通道,或者为什么需要等待组

I don't understand why this works with an unbuffered channel, or why a wait group is needed

在这段代码中,我调用了一个计算字符串中字母数量的函数,return 一个符文映射。为了利用并发性,我使用 goroutines 调用该函数:

func ConcurrentFrequency(l []string) FreqMap {
    var wg sync.WaitGroup
    wg.Add(len(l))
    m := FreqMap{}

    // Using unbuffered channel
    // ch := make(chan FreqMap, len(l))
    ch := make(chan FreqMap)

    for _, s := range l {
        go func(s string, ch chan<- FreqMap) {
            defer wg.Done()
            ch <- Frequency(s)
        }(s, ch)
    }
    go func() {
        wg.Wait()
        close(ch)
    }()

    for cm := range ch {
        for r, n := range cm {
            m[r] += n
        }
    }

    return m
}

如果我在不使用等待组和关闭通道的 goroutine 的情况下尝试此代码:

    go func() {
        wg.Wait()
        close(ch)
    }()

,然后我陷入僵局。

我不明白的是,为什么我能够在无缓冲通道上循环,并从中读取多个地图。

这是完整的程序: https://go.dev/play/p/zUwr_HvTT5w

并且并发方法仅比顺序方法快:

goos: linux
goarch: amd64
pkg: letter
cpu: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
BenchmarkSequentialFrequency
BenchmarkSequentialFrequency-2              2820            367128 ns/op           17571 B/op         13 allocs/op
BenchmarkConcurrentFrequency
BenchmarkConcurrentFrequency-2              4237            282632 ns/op           12682 B/op         72 allocs/op
PASS
ok      letter  3.320s

A for-range loop over a channel continues until the channel is closed.

如果删除最终关闭通道的 goroutine,for 循环永远不会终止。一旦所有的 goroutines 发送值都完成了,只剩下一个 goroutine 并且它永远被阻塞,等待通道关闭。

缓冲通道与此问题无关。他们只帮助处理被阻止的发件人,但这里的问题是被阻止的接收者。