V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
tqz
V2EX  ›  程序员

go channel 这段代码为什么报错

  •  
  •   tqz · 299 天前 · 1293 次点击
    这是一个创建于 299 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这段代码为什么报错

    func main() {
    	ch := make(chan int)
    	<-ch
    }
    
    fatal error: all goroutines are asleep - deadlock!
    goroutine 1 [chan receive]:
    main.main()
    

    我刚开始学习 go ,按照网上的教程说读取无缓冲通道时,如果没有数据写入就会一直阻塞,但实际上却报错了,难道是因为在 main 里面的缘故?或者是根本没有发送者的缘故?

    各位大佬们,请问学习 channel 有什么让人醍醐灌顶的提醒吗?感谢您的指点!

    补充:有无缓冲都报错

    
    func main() {
    	ch := make(chan int, 1)
    	//go func() {
    	//	time.Sleep(time.Second * 3)
    	//	ch <- 1
    	//}()
    	<-ch
    }
    
    第 1 条附言  ·  298 天前
    结贴,多谢各位。

    相当于 main 也是个 goroutine ,在 main 里面单独阻塞的话,也就是只有一个协程阻塞了,系统会判断死锁情况并 panic
    12 条回复    2023-08-04 10:39:25 +08:00
    tyrantZhao
        1
    tyrantZhao  
       299 天前
    main 也是个 channel ,so 瞅瞅是不是就死锁了?
    mcfog
        2
    mcfog  
       299 天前 via Android
    因为阻塞了,所以 all goroutines are asleep 。因为 all goroutines are asleep ,所以 deadlock 。因为 deadlock ,所以报错了
    weirdo
        3
    weirdo  
       299 天前
    all goroutines are asleep - deadlock!

    写的很清楚了,main 里面阻塞了,就相当于这个程序执行开出来的所有 goroutines 都 sleep 了,死锁了。
    ScepterZ
        4
    ScepterZ  
       299 天前
    相当于 go 有一点主动识别死锁的功能,他检查到程序已经不可能运行下去了,所以给你报错了,而不是真的卡主
    clikes
        5
    clikes  
       299 天前
    这里确实是阻塞了,但是这里报错是因为所有的 goroutine 都阻塞了,如果你想看这个现象的话 可以创建两个 goroutine ,然后阻塞其中一个。
    jinsp
        6
    jinsp  
       298 天前
    jinsp
        7
    jinsp  
       298 天前
    可以直接跟 GPT 学习
    alsas
        8
    alsas  
       298 天前
    main 函数启动也是一个 goroutine 死锁了
    lasuar
        9
    lasuar  
       298 天前
    KaynW
        10
    KaynW  
       298 天前
    golang 的检测机制, 当运行的 M 为 0 时就会这样, golang 认为出现了 deadlock
    sirz
        11
    sirz  
       298 天前
    ### GPT3.5 回复:

    这段代码报错的原因是因为您在 main 函数中创建了一个整型类型的通道 ch ,然后立即尝试从该通道接收数据。但是在没有其他协程往该通道发送数据的情况下,该操作会导致程序阻塞,因此编译器会报错。

    要解决这个问题,您可以通过以下方式之一:

    1. 在<-ch 操作之前,在另外一个协程中使用 go 关键字发送数据到通道,例如:go func() { ch <- 1 }()
    2. 使用 channel 的缓冲区,例如:ch := make(chan int, 1),这样就可以先往通道中写入一个数据,然后再进行接收操作。
    3. 删除<-ch 操作,这样代码将不再尝试从通道接收数据,不会引发阻塞。

    请根据您的需求选择适合的方法来修改代码。如果还有其他问题,请随时提问。


    ### GPT4 回复:

    这段代码中的错误源于它试图从一个没有接收任何值的通道中读取数据。在 Go 语言中,尝试从空的通道读取数据会导致程序阻塞。

    以下是你的代码:

    func main() {
    ch := make(chan int)
    <-ch // 这里尝试从空的通道读取数据,导致程序阻塞
    }
    要想解决该问题,你需要确保在尝试从通道 ch 读取数据之前,该通道已经接收到了某个值。以下是一种可能的解决方案:

    go
    func main() {
    ch := make(chan int)

    go func() { // 创建一个新的 goroutine 来向通道发送数据
    ch <- 1
    }()

    fmt.Println(<-ch) // 现在可以从通道中安全地读取数据
    }
    在这个修改后的版本中,我们创建了一个新的 goroutine 来向通道 ch 发送一个整数值,这样主函数就可以从 ch 中读取数据而不会被阻塞。
    zhangkunkyle
        12
    zhangkunkyle  
       298 天前   ❤️ 1
    未初始化的 channel
    1.读、写会死锁,关闭会 panic

    已初始化的无缓冲 channel
    1. 只写、只读会死锁
    2. 一个协程内顺序先读后写、先写后读会死锁
    3. 主协程先写,然后新开协程读会死锁(新开协程先读、然后主协程写就不会死锁了)
    4. 新开协程写,主协程读,如果写完不 close ,读的时候也会死锁

    已初始化的有缓冲 channel
    1. 只读会死锁,只写超过缓冲数会死锁
    2. 读写都有的情况下,写满了还写,读空了还读,会死锁
    3. 一个协程里写一定要在读之前,读空的会死锁
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3186 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 11:33 · PVG 19:33 · LAX 04:33 · JFK 07:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.