Golang文本处理中遇到的死锁问题(新手求助)
Golang文本处理中遇到的死锁问题(新手求助) 这是一个初学者问题,但我无法理解为什么会出现死锁。这段代码本应将字符串数组分成四块,通过 goroutine 发送到频率计数器,然后打印结果。
// Split load optimally across processor cores.
func WordCount(text string) {
//doing text processing here (omitted)
numberOfGroups := 4
piece := len(sentence) / numberOfGroups
//buffered channel, but it does not work better with an unbuffered one
wordChannel := make(chan map[string]int, numberOfGroups)
wg := new(sync.WaitGroup)
wg.Add(numberOfGroups)
for i := 0; i+piece < len(sentence); i += piece {
go processToCounting(sentence[i:i+piece], wordChannel, wg)
}
wg.Wait()
close(wordChannel)
fmt.Print(<-wordChannel)
}
func processToCounting(textSlice []string, wordChannel chan map[string]int, wg *sync.WaitGroup) {
freq := make(map[string]int)
for _, v := range textSlice {
freq[v]++
}
//does not work with defer either
wg.Done()
wordChannel <- freq
}
更多关于Golang文本处理中遇到的死锁问题(新手求助)的实战教程也可以访问 https://www.itying.com/category-94-b0.html
5 回复
非常感谢,我十分感激。确实,刚开始学习 Go 语言时会感到非常困惑。在其他练习中,我把 wg.Add(1) 放在了循环内部,所以我明白你在说什么。
嗨 @Dj_Sparks,
你需要将 wg.Wait() 放入一个 goroutine 中,这样它就不会阻塞。例如,通常你会看到这样实现:
go func() {
wg.Wait()
close(wordChannel)
}()
fmt.Print(<-wordChannel)
当然。在你的示例中,你向 wg 添加了 numberOfGroups。但是有可能 for i := 0; i+piece < len(sentence); i += piece 这行代码执行的次数少于 numberOfGroups 次(4次),你永远没有返回第4次 wg.Done()。
例如,你可以改为这样做,并在每次循环时增加 wg 计数器:
for i := 0; i+piece < len(sentence); i += piece {
wg.Add(1)
go processToCounting(sentence[i:i+piece], wordChannel, wg)
}
但你仍然可能需要像这样完成:
go func() {
wg.Wait()
close(wordChannel)
}()
for val := range wordChannel {
fmt.Println(val)
}
编辑:或者在你的情况下,最终计数可以这样做:
go func() {
wg.Wait()
close(wordChannel)
}()
frequencyMap := map[string]int{}
for val := range wordChannel {
for k, v := range val {
frequencyMap[k] += v
}
}
fmt.Println(frequencyMap)
希望这能讲得通!
问题在于代码在关闭通道后只从通道读取一次,但实际发送了多个值。当有多个 goroutine 向通道发送数据时,只读取一次会导致其他发送操作被阻塞,从而产生死锁。
以下是修正后的代码:
func WordCount(text string) {
// 假设 sentence 是字符串切片
sentence := strings.Fields(text) // 示例:将文本分割成单词
numberOfGroups := 4
if len(sentence) < numberOfGroups {
numberOfGroups = len(sentence)
}
piece := len(sentence) / numberOfGroups
wordChannel := make(chan map[string]int, numberOfGroups)
wg := new(sync.WaitGroup)
wg.Add(numberOfGroups)
for i := 0; i < len(sentence); i += piece {
end := i + piece
if end > len(sentence) {
end = len(sentence)
}
go processToCounting(sentence[i:end], wordChannel, wg)
}
// 使用单独的 goroutine 等待并关闭通道
go func() {
wg.Wait()
close(wordChannel)
}()
// 读取所有结果
for result := range wordChannel {
fmt.Println(result)
}
}
func processToCounting(textSlice []string, wordChannel chan map[string]int, wg *sync.WaitGroup) {
defer wg.Done() // 使用 defer 确保 Done() 被调用
freq := make(map[string]int)
for _, v := range textSlice {
freq[v]++
}
wordChannel <- freq
}
主要修改:
- 使用
range循环读取通道中的所有值 - 在单独的 goroutine 中等待并关闭通道
- 使用
defer wg.Done()确保计数器正确递减 - 添加边界检查防止切片越界
- 处理当文本长度小于分组数的情况
这样确保所有发送到通道的值都被正确接收,避免了死锁。

