为了账号安全,请及时绑定邮箱和手机立即绑定

为什么在 Golang 中发送超过缓冲通道大小的值会导致死锁错误?

为什么在 Golang 中发送超过缓冲通道大小的值会导致死锁错误?

Go
慕村9548890 2022-06-01 15:47:28
// By default channels are _unbuffered_, meaning that they// will only accept sends (`chan <-`) if there is a// corresponding receive (`<- chan`) ready to receive the// sent value. _Buffered channels_ accept a limited// number of  values without a corresponding receiver for// those values.package mainimport "fmt"func main() {    // Here we `make` a channel of strings buffering up to    // 2 values.    messages := make(chan string, 2)    // Because this channel is buffered, we can send these    // values into the channel without a corresponding    // concurrent receive.    messages <- "buffered"    messages <- "channel"    messages <- "channel1" //I added this.     // Later we can receive these two values as usual.    fmt.Println(<-messages)    fmt.Println(<-messages)}它抛出的错误:fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:main.main()    /tmp/sandbox795158698/prog.go:23 +0x8d问题:我们不能发送比缓冲区大小更多的值吗?为什么错误说“所有 goroutines 都在睡觉 - 死锁!” 当代码中没有 goroutines 时?为什么会出现这种僵局?请解释?
查看完整描述

2 回答

?
墨色风雨

TA贡献1853条经验 获得超6个赞

写入完整通道的尝试将被阻塞,直到其他一些 goroutine 从中读取。在您的程序中,没有其他 goroutines。因此,当您写入完整通道时,主 goroutine 会阻塞,并且由于没有其他 goroutine,因此主 goroutine 不可能继续进行。那是一个僵局。



查看完整回答
反对 回复 2022-06-01
?
慕工程0101907

TA贡献1887条经验 获得超5个赞

添加到上述答案: https ://stackoverflow.com/a/61512364/4106031


package main


import (

    "fmt"

    "github.com/practo/klog/v2"

    "os"

    "os/signal"

    "syscall"

    "time"

)


func producer(msgBuf chan<- string) {

    for i := 0; ; i++ {

        fmt.Printf("sent: %d\n", i)

        msgBuf <- fmt.Sprintf("%d", i)

        time.Sleep(1 * time.Second)

    }

}


func process(msgBuf <-chan string) {

    time.Sleep(10 * time.Second)

    for {

        select {

        case msg := <-msgBuf:

            fmt.Printf("processing: %v\n", msg)

            time.Sleep(10 * time.Second)

            fmt.Printf("processed: %v\n", msg)

        }

    }

}


func main() {

    msgBuf := make(chan string, 2)

    go producer(msgBuf)

    go process(msgBuf)


    sigterm := make(chan os.Signal, 1)

    signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM)

    for {

        select {

        default:

        case <-sigterm:

            klog.Info("SIGTERM signal received")

            os.Exit(1)

        }

    }

}


当您在不同的 go 例程中运行它们时,这不会导致死锁。


查看完整回答
反对 回复 2022-06-01
  • 2 回答
  • 0 关注
  • 198 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信