猿问

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

// 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 main


import "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

问题:

  1. 我们不能发送比缓冲区大小更多的值吗?

  2. 为什么错误说“所有 goroutines 都在睡觉 - 死锁!” 当代码中没有 goroutines 时?

  3. 为什么会出现这种僵局?请解释?


慕村9548890
浏览 199回答 2
2回答

墨色风雨

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

慕工程0101907

添加到上述答案: https ://stackoverflow.com/a/61512364/4106031package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "github.com/practo/klog/v2"&nbsp; &nbsp; "os"&nbsp; &nbsp; "os/signal"&nbsp; &nbsp; "syscall"&nbsp; &nbsp; "time")func producer(msgBuf chan<- string) {&nbsp; &nbsp; for i := 0; ; i++ {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("sent: %d\n", i)&nbsp; &nbsp; &nbsp; &nbsp; msgBuf <- fmt.Sprintf("%d", i)&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(1 * time.Second)&nbsp; &nbsp; }}func process(msgBuf <-chan string) {&nbsp; &nbsp; time.Sleep(10 * time.Second)&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case msg := <-msgBuf:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("processing: %v\n", msg)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(10 * time.Second)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("processed: %v\n", msg)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; msgBuf := make(chan string, 2)&nbsp; &nbsp; go producer(msgBuf)&nbsp; &nbsp; go process(msgBuf)&nbsp; &nbsp; sigterm := make(chan os.Signal, 1)&nbsp; &nbsp; signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM)&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; case <-sigterm:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; klog.Info("SIGTERM signal received")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; os.Exit(1)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}当您在不同的 go 例程中运行它们时,这不会导致死锁。
随时随地看视频慕课网APP

相关分类

Go
我要回答