当前位置: 首页 > 面试题库 >

为什么在同一goroutine中使用未缓冲的通道会导致死锁?

全誉
2023-03-14
问题内容

我敢肯定对这种琐碎的情况有一个简单的解释,但是我对go并发模型是陌生的。

当我运行这个例子

package main

import "fmt"

func main() {
    c := make(chan int)    
    c <- 1   
    fmt.Println(<-c)
}

我收到此错误:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /home/tarrsalah/src/go/src/github.com/tarrsalah/tour.golang.org/65.go:8 +0x52
exit status 2

为什么呢

包装c <-成一个goroutine使示例按预期运行

package main

import "fmt"

func main() {
    c := make(chan int)        
    go func(){
       c <- 1
    }()
    fmt.Println(<-c)
}

再次,为什么?

请,我需要深入的解释,而不仅仅是如何消除死锁并修复代码。


问题答案:

从文档中:

如果通道未缓冲,则发送方将阻塞,直到接收方收到该值为止。如果通道具有缓冲区,则发送方仅阻塞该值,直到将值复制到该缓冲区为止;否则,发送方才阻塞。如果缓冲区已满,则意味着要等到某些接收器检索到一个值。

否则说:

  • 当频道已满时,发送方等待另一个goroutine通过接收来腾出空间
  • 您会看到一个未缓冲的通道总是一个完整的通道:必须有另一个goroutine来处理发送方发送的内容。

这条线

c <- 1

阻塞,因为通道没有缓冲。由于没有其他goroutine可以接收该值,因此情况无法解决,这是一个僵局。

您可以将频道创建更改为

c := make(chan int, 1)

这样,频道在被阻止之前就可以容纳一个项目。

但这不是并发的意义所在。通常,没有其他goroutine不会使用通道来处理放入内部的内容。您可以这样定义一个接收goroutine:

func main() {
    c := make(chan int)    
    go func() {
        fmt.Println("received:", <-c)
    }()
    c <- 1   
}

示范



 类似资料:
  • 请问上述代码的第70行换成第71行注释的内容时,为什么会造成死循环。 题目: https://www.acwing.com/problem/content/174/

  • 最近我在写一些复杂的基于RX的流程,发现它总是在特定情况下产生死锁。我花了几个小时才找出问题所在,似乎可以在这个简单的示例中重现: 此程序应打印以下值:11、21、22、31、32、33、。。。,通常,值可以表示为XY。每组X中的值的顺序可以是随机的,但组的顺序应该是升序。如果previous仍在计算,则不应发出新组(这是我的原始情况)。 问题是,如果您运行这段代码,您将只看到前几个元素的输出-我

  • 问题内容: 我需要使用单个任务队列和单个结果队列来启动许多工作程序。每个工人都应该以不同的goroutine开始。我需要等到所有工作人员都将完成并且任务队列将为空后再退出程序。我已经准备了goroutine同步的小例子。主要思想是我们将排队的任务计数,并等待所有工人完成工作。但是当前的实现有时会遗漏值。为什么会发生这种情况以及如何解决问题?示例代码: 问题答案: 使用sync.WaitGroup等

  • 默认情况下,通道是不带缓冲区的。 发送端发送数据,同时必须又接收端相应的接收数据。 而带缓冲区的通道则允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。 不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。 package main imp

  • 问题内容: 我有一个具有高 缓冲区I / O 的客户端SQL Server 。 我检查了长时间运行的查询,添加了新索引,并且服务器上没有锁。是磁盘问题吗? 问题答案: 首先尝试检查您的磁盘延迟时间是否在阈值内。 您可以检查此链接以配置Perfmon:SQL Server磁盘性能指标-第1部分- 最重要的磁盘性能指标 该链接还提供了一些工具,可以对您的IO进行压力测试并获得报告。 如何使用SQLIO

  • 问题内容: 注意: 这是不是重复,请仔细阅读题目 сarefully报价: 真正的问题是为什么代码有时在不应该运行的情况下仍然有效。即使没有lambda,该问题也会重现。这使我认为可能存在JVM错误。 在http://codingdict.com/questions/122889的评论中,我试图找出原因,导致代码行为从一个起点到另一个起点有所不同,而该讨论的参与者为我提供了一个建议,以创建一个单独