这是作业和初学者的问题。因为我发现了一个错误,所以我编辑了问题。
我正在尝试从文本中创建并行频率图,但是在上一次操作中出现错误(缩小图)
代码似乎可以正常工作。
如果我关闭频道,则会出现错误: “恐慌:在封闭频道上发送”
如果我不关闭频道,则会得到: “致命错误:所有goroutine都在睡觉-死锁!”
func WordCount(text string) {
text = strings.ToLower(text)
re := regexp.MustCompile("\\w+")
sentence := re.FindAllString(text, -1)
numberOfGroups := 4
piece := len(sentence) / numberOfGroups
wordChannel := make(chan map[string]int)
wg := new(sync.WaitGroup)
wg.Add(numberOfGroups)
for i := 0; i < numberOfGroups; i ++ {
go processToCounting(sentence[i*piece:(i+1)*piece], wordChannel, wg)
}
wg.Wait()
fmt.Print(<-wordChannel)
fmt.Print("\n")
finalMap := make(map[string]int)
close(wordChannel)
for i := 0; i < numberOfGroups; i++ {
for k, v := range <- wordChannel {
finalMap[k] += v
}
}
}
func processToCounting(textSlice []string, wordChannel chan map[string]int, wg *sync.WaitGroup) {
freq := make(map[string]int)
for _, v := range textSlice {
freq[v]++
}
wg.Done()
wordChannel <- freq
}
答案 0 :(得分:0)
第一季度:为什么close(wordChannel)
引发恐慌
A:
wg.Done()
放在结果插入频道之前第二季度:为什么出现僵局。
A:fmt.Print(<-wordChannel)
从通道中读取一条消息,因此最后一个循环无法读取numberOfGroups
消息。它会永远等待最后一条消息。
for i := 0; i < numberOfGroups; i++ {
for k, v := range <- wordChannel {
finalMap[k] += v
}
}
答案 1 :(得分:0)
1。第一个问题:恐慌
如果我关闭频道,则会收到错误消息:“紧急:在关闭的频道上发送”
为什么?您的goroutine之一正在尝试写入已在调用(主)goroutine中关闭的通道。就您而言,使用WordCount
函数。
在当前版本的代码中,panic
is not reproducible和我的测试语句一起出现,但是您很容易造成这种情况,例如如果您会在close(wordChannel)
之前致电wg.Wait()
。
让我们看看processToCounting
中的错误,它可能会导致panic
:
wg.Done() // tells to the WaitGroup that the gouroutine is Done (decrements the counter of goroutines)
wordChannel <- freq // trying to write to the channel
在实际写入通道之前,wg.Done()
向WaitGroup
发出信号,表明goroutine为Done
。在某些时候调用goroutine(WordCount
函数)认为所有gouroutine都已完成(wg.Wait()
行)并关闭了通道。但是您的goroutine之一尚未完成写入,将尝试写入关闭的通道。然后您将得到panic
。
如何解决:
在processToCounting
函数中使用defer
defer wg.Done() // triggers wg.Done right before the function returns (but after writing to the channel in your case)
阅读内容:
在A Tour of Go / Concurrency中查找初学者
在封闭的频道上发送会引起恐慌。
和文档:close
发送到或关闭已关闭的频道会导致运行时恐慌。
2。第二个问题:死锁
如果我不关闭通道,则会得到:“致命错误:所有goroutine都在睡眠-死锁!”
您有一个用于从通道读取的for循环。此for循环将永远锁定。等待通道中的新值,但是没有人会再写在那里。
i:=范围c的循环反复从通道接收值,直到关闭为止。
并查看Channels
的文档接收者总是阻塞,直到有数据要接收为止