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 编程语言

Go Playground - Go 编程语言

这个错误是因为程序中的 goroutine 进入了死锁状态。具体来说,main 函数中的代码在没有其他 goroutine 从通道接收数据的情况下,直接向无缓冲通道 ch 发送数据,导致发送操作阻塞,而后续的 for 循环接收操作无法执行,因此所有 goroutine(这里只有主 goroutine)都处于休眠状态。

问题分析:

  1. 无缓冲通道要求发送和接收操作必须同时准备好,否则会阻塞
  2. 代码中 ch <- aw 发送操作会阻塞主 goroutine
  3. 由于主 goroutine 被阻塞,后面的 for 循环无法执行接收操作
  4. 最终导致死锁

解决方案:使用 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() // 等待接收完成
}

以上三种方案都可以避免死锁,根据具体的使用场景选择合适的方案。

回到顶部