为什么在 Golang 中发送大于缓冲通道大小的值会导致死锁错误?
Why does sending a value more than buffered channel size in Golang causes deadlock error?
// 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
问题:
- 我们不能发送比缓冲区大小更多的值吗?
- 为什么会出现错误
"all goroutines are asleep - deadlock!" 当没有 goroutines 时
在代码中?
- 为什么会出现这种僵局?请解释一下?
尝试写入一个完整的通道将被阻塞,直到其他 goroutine 从中读取。在您的程序中,没有其他 goroutine。因此,当您写入完整通道时,主 goroutine 会阻塞,并且由于没有其他 goroutine,因此主 goroutine 不可能继续前进。那就是死锁。
添加到上面的答案:
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 例程中。
// 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
问题:
- 我们不能发送比缓冲区大小更多的值吗?
- 为什么会出现错误 "all goroutines are asleep - deadlock!" 当没有 goroutines 时 在代码中?
- 为什么会出现这种僵局?请解释一下?
尝试写入一个完整的通道将被阻塞,直到其他 goroutine 从中读取。在您的程序中,没有其他 goroutine。因此,当您写入完整通道时,主 goroutine 会阻塞,并且由于没有其他 goroutine,因此主 goroutine 不可能继续前进。那就是死锁。
添加到上面的答案:
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 例程中。