当前位置: 首页 > 知识库问答 >
问题:

与make通道相关的奇怪死锁

仲孙华奥
2023-03-14

我遇到了围棋频道的奇怪行为。问题描述如下。

package main

import "fmt"

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

    fmt.Println("len:", len(ch))
    fmt.Println("cap:", cap(ch))
    fmt.Println("is nil:", ch == nil)
                                                                         
    go func(ch chan int){
        ch <- 233
    }(ch)

    fmt.Println(<- ch)

}

当我运行上面的代码时,我得到如下结果:

len: 0
cap: 0
is nil: false
233

频道ch的len和cap看起来很复杂,但代码仍然有效。当我运行此代码时:

package main

import "fmt"

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

    fmt.Println("len:", len(ch))
    fmt.Println("cap:", cap(ch))
    fmt.Println("is nil:", ch == nil)
                                                                         
    ch <- 233 // Here changes!

    fmt.Println(<- ch)

}

结果是:len:0 cap:0是nil:false致命错误:所有goroutine都处于Hibernate状态-死锁!

goroutine 1 [chan send]:
main.main()
    /tmp/sandbox640280398/main.go:12 +0x340

更重要的是,当我更改第二个代码块时,如下所示:package main

import "fmt"

func main() {
    ch := make(chan int, 1) //Here changes!

    fmt.Println("len:", len(ch))
    fmt.Println("cap:", cap(ch))
    fmt.Println("is nil:", ch == nil)
                                                                         
    ch <- 233

    fmt.Println(<- ch)

}

事情又起了作用,我得到了:

len: 0
cap: 1
is nil: false
233

那么,谁能告诉我以下问题:

>

  • 为什么使(chan int)返回一个具有零len和零Cap的通道,但仍然可以在第一个代码段中很好地工作?

    为什么第二个代码使用main函数中的通道而不是新的goroutine导致死锁?

    为什么我在第三个代码中添加一个cap参数可以解决这个问题?

    信道(在第一和第二代码中)与零信道之间有什么区别?

  • 共有1个答案

    彭成天
    2023-03-14

    可以创建两种类型的通道:缓冲通道和非缓冲通道
    缓冲通道是那些具有容量的通道:make(chan int,10)
    缓冲通道允许您向它们发送与其容量相同的消息,而不会被阻止
    无缓冲通道没有容量,这就是为什么发送的goroutine将被阻止,直到另一个goroutine从中接收。

    1.它是无缓冲信道。你的主goroutine被阻止从通道接收,直到新的goroutine发送消息给它。

    2.由于您使用的是非缓冲通道,因此在收到另一个发送goroutine之前,您的发送goroutine将被阻止,但除了主goroutine之外,您没有其他goroutine,因此程序处于死锁状态。

    3.因为有缓冲的goroutine。它的容量为1,所以发送一条消息到它,然后在同一个goroutine中接收它是没有问题的。但是如果您尝试向它发送超过1条消息,您将被阻止。ch

    4.没有得到你的意思...,但如果你试图接收或发送到一个零通道,你会被阻止:var ch chan int;

     类似资料:
    • 一个js转义问题 这是在浏览器的控制台,为什么为出现这种结果,如果要输出'a\b\c\d'这样,请问题如何写

    • 我们使用的是tomcat7,maxthreads=“200”和maxconnections=10000。我们在主存之外提供所有数据,因此每个HTTP请求完成得非常快,但我们有大量用户在进行非常简单的交互(这是高中主题选择)。但是,我们似乎不太可能有10,000个用户同时打开他们的浏览器在我们的页面上。 我的问题有几个部分: 可能是“maxconnections”参数导致了我们的问题吗? 有什么理由

    • 也许有人能解释以下行为--希望能找到可行的解决办法...多谢了。 有什么想法吗?

    • 有没有办法获得与特定youtube频道相关的频道列表。就像我们在youtube页面上一样?我知道有一个api可以获取与视频相关的视频,但我如何为频道做到这一点。以下网站似乎正在这样做: http://vidooly.com/channel/UCbTLwN10NoCU4WDzLf1JMOA#

    • 问题内容: 这仅适用于至少两个发送到通道的设备。在deviceChan中只有一台设备时,该功能不会接收任何东西。通道在WriteDeviceToFile到达之前消失了吗? 问题答案: 返回时程序退出。写入文件之前没有任何阻止

    • 我在包上收到以下编译器错误: 包com.core.cronjob.mapping; 错误 : 内部编译器错误: java.lang.非法描述异常: 信息不能为空在组织.eclipse.jdt.内部.编译器.codegen.StackMapFrame.addStackItem(堆栈映射帧.java:81) 我不认为这是代码。我正在使用蚂蚁1.9.4来构建项目和Eclips Mars.1版本。(4.5