与 make 通道相关的奇怪死锁
Wierd deadlock related with make channel
我遇到了 Go 频道的奇怪行为。问题描述如下
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)
}
结果变成了:
长度:0
上限:0
为零:假
致命错误:所有 goroutines 都睡着了 - 死锁!
goroutine 1 [chan send]:
main.main()
/tmp/sandbox640280398/main.go:12 +0x340
更重要的是,当我像下面这样更改第二个代码片段时:
主包
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
所以,谁能告诉我以下问题:
为什么 make(chan int) return 具有 zero len 和 [=38 的频道=]零 上限,但在第一个代码段中仍然可以正常工作?
为什么第二个代码在主函数中使用通道而不是新的goroutine导致死锁?
为什么我在第三个代码的make中加一个cap参数可以解决问题?
通道(在第一个和第二个代码中)与 nil 通道有什么区别?
您可以创建两种类型的通道:缓冲通道和非缓冲通道。
缓冲通道是那些具有容量的通道:make(chan int, 10)
缓冲通道允许您向其中发送与其容量相同数量的消息而不会被阻塞。
无缓冲通道没有容量,这就是为什么您的发送 goroutine 将被阻塞,直到另一个 goroutine 收到它。
1. 是无缓冲通道。在新的 goroutine 向它发送消息之前,你的主 goroutine 在从通道接收时被阻塞。
2. 因为你使用的是无缓冲通道,你的发送 goroutine 被阻塞,直到另一个 goroutine 从它接收,但是除了主 goroutines 你没有其他 goroutines,所以程序在僵局。
3. 因为缓冲 goroutine。它的容量为 1,因此向它发送一条消息然后在同一个 goroutine 中接收它不会有问题。但是,如果您尝试向它发送超过 1 条消息,您将被阻止。 ch <- 233; ch <- 233
- 此代码将导致死锁。
4. 明白你的意思...,但如果你尝试接收或发送到一个 nil 频道,你将被阻止:var ch chan int; <-ch
或 var ch chan int; ch <- 1
我遇到了 Go 频道的奇怪行为。问题描述如下
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)
}
结果变成了: 长度:0 上限:0 为零:假 致命错误:所有 goroutines 都睡着了 - 死锁!
goroutine 1 [chan send]:
main.main()
/tmp/sandbox640280398/main.go:12 +0x340
更重要的是,当我像下面这样更改第二个代码片段时: 主包
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
所以,谁能告诉我以下问题:
为什么 make(chan int) return 具有 zero len 和 [=38 的频道=]零 上限,但在第一个代码段中仍然可以正常工作?
为什么第二个代码在主函数中使用通道而不是新的goroutine导致死锁?
为什么我在第三个代码的make中加一个cap参数可以解决问题?
通道(在第一个和第二个代码中)与 nil 通道有什么区别?
您可以创建两种类型的通道:缓冲通道和非缓冲通道。
缓冲通道是那些具有容量的通道:make(chan int, 10)
缓冲通道允许您向其中发送与其容量相同数量的消息而不会被阻塞。
无缓冲通道没有容量,这就是为什么您的发送 goroutine 将被阻塞,直到另一个 goroutine 收到它。
1. 是无缓冲通道。在新的 goroutine 向它发送消息之前,你的主 goroutine 在从通道接收时被阻塞。
2. 因为你使用的是无缓冲通道,你的发送 goroutine 被阻塞,直到另一个 goroutine 从它接收,但是除了主 goroutines 你没有其他 goroutines,所以程序在僵局。
3. 因为缓冲 goroutine。它的容量为 1,因此向它发送一条消息然后在同一个 goroutine 中接收它不会有问题。但是,如果您尝试向它发送超过 1 条消息,您将被阻止。 ch <- 233; ch <- 233
- 此代码将导致死锁。
4. 明白你的意思...,但如果你尝试接收或发送到一个 nil 频道,你将被阻止:var ch chan int; <-ch
或 var ch chan int; ch <- 1