Golang中为什么会出现所有goroutine都处于休眠状态的错误
Golang中为什么会出现所有goroutine都处于休眠状态的错误
package main
import (
"fmt"
)
func main() {
type EXP struct {
A string
b string
}
ch := make(chan EXP)
aw := EXP{"asdasd", "ASDASD"}
ch <- aw
for i := range ch {
fmt.Println(i)
}
}
5 回复
如果通道是无缓冲的,在同一goroutine中无法同时执行通道的发送和接收操作。
更多关于Golang中为什么会出现所有goroutine都处于休眠状态的错误的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
由于 ch 是无缓冲的,您的主协程将在 ch <- aw 处休眠,直到另一个协程从该通道读取数据。
你几乎无法在同一个goroutine中对同一个channel进行读写操作。即使channel有缓冲,上面的例子也会出现死锁。因为对channel进行range操作会一直锁定,直到channel中的所有项目都被读取完毕。
引用 Akezhan_Esbolatov 的发言:
package main import ( "fmt" ) func main() { type EXP struct { A string b string } ch := make(chan EXP) aw := EXP{"asdasd", "ASDASD"} ch <- aw for i := range ch { fmt.Println(i) } }
Go Playground - Go 编程语言
这个错误是因为程序中的 goroutine 进入了死锁状态。具体来说,main 函数中的代码在没有其他 goroutine 从通道接收数据的情况下,直接向无缓冲通道 ch 发送数据,导致发送操作阻塞,而后续的 for 循环接收操作无法执行,因此所有 goroutine(这里只有主 goroutine)都处于休眠状态。
问题分析:
- 无缓冲通道要求发送和接收操作必须同时准备好,否则会阻塞
- 代码中
ch <- aw发送操作会阻塞主 goroutine - 由于主 goroutine 被阻塞,后面的
for循环无法执行接收操作 - 最终导致死锁
解决方案:使用 goroutine 来异步发送或接收数据
方案一:使用 goroutine 发送数据
package main
import (
"fmt"
)
func main() {
type EXP struct {
A string
b string
}
ch := make(chan EXP)
// 使用 goroutine 发送数据
go func() {
aw := EXP{"asdasd", "ASDASD"}
ch <- aw
close(ch) // 发送完成后关闭通道
}()
// 在主 goroutine 中接收数据
for i := range ch {
fmt.Println(i)
}
}
方案二:使用缓冲通道
package main
import (
"fmt"
)
func main() {
type EXP struct {
A string
b string
}
// 创建有缓冲的通道
ch := make(chan EXP, 1)
aw := EXP{"asdasd", "ASDASD"}
ch <- aw
close(ch) // 发送完成后关闭通道
for i := range ch {
fmt.Println(i)
}
}
方案三:使用 goroutine 接收数据
package main
import (
"fmt"
"sync"
)
func main() {
type EXP struct {
A string
b string
}
ch := make(chan EXP)
var wg sync.WaitGroup
wg.Add(1)
// 使用 goroutine 接收数据
go func() {
defer wg.Done()
for i := range ch {
fmt.Println(i)
}
}()
aw := EXP{"asdasd", "ASDASD"}
ch <- aw
close(ch) // 发送完成后关闭通道
wg.Wait() // 等待接收完成
}
以上三种方案都可以避免死锁,根据具体的使用场景选择合适的方案。


