Gho*_*ies 8 for-loop go goroutine
我试图解决这个问题的练习:
编写一个程序,使用并行计算计算文本中字母的频率.
基本上,我有一个FreqMap类型:
type FreqMap map[rune]int
Run Code Online (Sandbox Code Playgroud)
和一个Frequency功能:
func Frequency(s string) FreqMap {
m := make(FreqMap)
for _, v := range s {
m[v]++
}
return m
}
Run Code Online (Sandbox Code Playgroud)
Exercism提供了一个使用递归实现并发版本的示例,但我想使用for 循环实现我自己的版本.我提出了以下解决方案,但不起作用:
func ConcurrentFrequency(l []string) FreqMap {
c := make(chan FreqMap)
for i := 0; i < len(l); i++ {
go func(i int) {
c <- Frequency(l[i])
}(i)
}
return <- c
}
Run Code Online (Sandbox Code Playgroud)
这似乎只在1次迭代后返回,c似乎只包含1个goroutine的结果; 如果我添加一个,我会得到相同的结果sync.WaitGroup.
你能解释一下我在这里缺少什么吗?
预先感谢您的帮助!
您的代码似乎只进行了一次迭代,因为ConcurrentFrequency从通道返回了第一个值,仅此而已。我问你想要这样的东西:
func ConcurrentFrequency(l []string) chan FreqMap {
c := make(chan FreqMap)
go func() {
var wg sync.WaitGroup
wg.Add(len(l))
for _, s := range l {
go func(s string) {
defer wg.Done()
c <- Frequency(s)
}(s)
}
wg.Wait()
close(c)
}()
return c
}
Run Code Online (Sandbox Code Playgroud)
现在,它返回地图的通道,您可能想将这些通道合并为单独的地图:
func main() {
m := make(FreqMap)
for v := range ConcurrentFrequency([]string{"foo", "bar","zoo"}) {
for k, v := range v {
m[k] += v
}
}
fmt.Println(m)
}
Run Code Online (Sandbox Code Playgroud)
较长的解释不适合评论:
在for _, s := range l循环中,所有goroutine都将写入同一通道,但是由于该通道未缓冲,因此将第一个值写入该通道后,它就已“满”,这意味着无法将其他值写入该通道。因此,循环中只有一个goroutine可以完成,并且wg.Done只能调用一次。因此,如果源数组具有多个字符串,则其他gorutines将无法完成,直到某些东西开始消耗通道中的值。但是在您的版本中,wg.Wait由于并非所有goroutine都已完成,因此它会卡在其中,因此ConcurrentFrequency无法将通道返回给使用者。用我编写的方式ConcurrentFrequency,可以将cannel返回给使用者,并且这(从通道读取)可以使其他Frequency(s)调用写入通道。
| 归档时间: |
|
| 查看次数: |
3247 次 |
| 最近记录: |