我不明白为什么它可以与未封闭的频道一起使用,或者为什么需要等待组
在此代码中,我调用一个函数,该函数计算字符串中字母的数量,然后返回符文的地图。为了利用并发性,我使用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
}
如果我在不使用WaitGroup和关闭通道的Goroutine的情况下尝试此代码:
go func() {
wg.Wait()
close(ch)
}()
,然后我会陷入僵局。
我不明白的是,为什么我能够循环循环,并从中读取多个地图。
这是完整的程序: https://go.dev/play/pplay/zuwr_hvtt5w
和conterent Method an而不是顺序方法:
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
In this code, I call a function which counts the number of letters in a string, and return a map of runes. To leverage concurrency, I call the function using 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
}
If I try this code without using a waitgroup and the goroutine which closes the channel:
go func() {
wg.Wait()
close(ch)
}()
, then I get a deadlock.
What I don't understand, is why I am able to loop over the unbuffered channel, and read multiple maps from it.
This is the full program:
https://go.dev/play/p/zUwr_HvTT5w
And the concurrent method is barely faster than the sequential method:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在通道上的范围循环一直持续到通道关闭。
如果您删除最终关闭通道的goroutine,则FO循环永远不会终止。一旦所有goroutines发送值都完成,只剩下一个goroutine,并且永远被阻塞,等待关闭通道。
缓冲通道与此问题无关。它们仅帮助阻止发件人,但这里的问题是一个被阻塞的接收器。
A for-range loop over a channel continues until the channel is closed.
If you remove the goroutine that eventually closes the channel, the for loop can never terminate. Once all goroutines sending values are done there is only one goroutine remaining and it is blocked forever, waiting for the channel to be closed.
Buffered channels have nothing to do with this problem. They only help with blocked senders, but here the problem is a blocked receiver.