Golang中如何解决所有goroutine陷入休眠的死锁错误
Golang中如何解决所有goroutine陷入休眠的死锁错误 我正在尝试编写一个处理大量数据的代码,并希望使用并发。
它需要按相同顺序打印行,但单词应保持正确顺序(这部分工作正常)。
然而,我不断收到“致命错误:所有goroutine都已休眠 - 死锁!”的错误,并且我的行没有按相同顺序排列。
你好,
你必须在主线程中等待 wg,不需要为它创建一个 goroutine。你应该在一个 goroutine 中对结果进行范围遍历,以避免阻塞主线程。
更多关于Golang中如何解决所有goroutine陷入休眠的死锁错误的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好 Skillian,
你的代码确实解决了死锁问题,但排序仍然存在问题。我做了一些修改,有助于保持行的顺序。
- 在扫描每一行并进行排序之后,我将该行写入结果,并为每个 goroutine 添加了一个等待,而不是一次性等待所有 goroutine。
请参考“请参考位于 Go Playground - The Go Programming Language 的代码”中请求的修复,并告知这是否是您所期望的
你的主 goroutine 正在循环读取 results 通道,而负责关闭该通道的 goroutine 直到循环结束后才会启动。循环会对所有结果调用 writeToFile,但随后会等待通道中永远不会再出现的新结果。
我建议添加一个单独的 goroutine 来负责将结果写入文件,并为其使用第二个等待组。流程基本如下:
- 创建消费者等待组和 goroutine
- 创建工作器等待组和 goroutines。当它们完成时,确保调用 Done。
- 在工作器等待组上调用 Wait。它会在最后一个工作器完成后返回。然后关闭结果通道,并等待消费者的等待组完成。
示例:
func main() {
fmt.Println("hello world")
}
在Golang中,当所有goroutine都处于等待状态且无法继续执行时,就会发生死锁错误。根据你提供的代码,问题主要在于通道的使用和goroutine同步机制。
以下是修正后的代码示例:
package main
import (
"fmt"
"strings"
"sync"
)
func main() {
text := "Hello world\nThis is a test\nConcurrency in Go"
lines := strings.Split(text, "\n")
// 使用带缓冲的通道
ch := make(chan string, len(lines))
var wg sync.WaitGroup
// 启动goroutine处理每一行
for i, line := range lines {
wg.Add(1)
go func(idx int, l string) {
defer wg.Done()
words := strings.Fields(l)
for j, w := range words {
words[j] = fmt.Sprintf("Word %d: %s", j+1, w)
}
// 将处理结果发送到通道
ch <- fmt.Sprintf("Line %d: %s", idx+1, strings.Join(words, " "))
}(i, line)
}
// 等待所有goroutine完成
go func() {
wg.Wait()
close(ch)
}()
// 收集结果
var results []string
for result := range ch {
results = append(results, result)
}
// 按顺序输出
for _, result := range results {
fmt.Println(result)
}
}
关键修改点:
-
使用带缓冲的通道:
make(chan string, len(lines))创建了一个有足够缓冲区的通道,避免发送阻塞 -
正确的WaitGroup使用:每个goroutine开始时调用
wg.Add(1),结束时调用wg.Done() -
独立的关闭通道goroutine:在单独的goroutine中等待所有工作完成后再关闭通道
-
保持顺序的数据结构:使用slice收集结果,而不是依赖通道的顺序
如果你需要严格保持行顺序,可以使用以下版本:
package main
import (
"fmt"
"strings"
"sync"
)
func main() {
text := "Hello world\nThis is a test\nConcurrency in Go"
lines := strings.Split(text, "\n")
type result struct {
idx int
output string
}
ch := make(chan result, len(lines))
var wg sync.WaitGroup
for i, line := range lines {
wg.Add(1)
go func(idx int, l string) {
defer wg.Done()
words := strings.Fields(l)
for j, w := range words {
words[j] = fmt.Sprintf("Word %d: %s", j+1, w)
}
ch <- result{
idx: idx,
output: fmt.Sprintf("Line %d: %s", idx+1, strings.Join(words, " ")),
}
}(i, line)
}
go func() {
wg.Wait()
close(ch)
}()
// 按原始顺序收集结果
results := make([]string, len(lines))
for r := range ch {
results[r.idx] = r.output
}
for _, r := range results {
fmt.Println(r)
}
}
这个版本通过包含索引信息,确保输出顺序与输入顺序完全一致。

