容量为0时
channel容量为0时的几种情况
正常输出
func demo() {
c := make(chan int ,0)
go func() {
c <- 1
}()
//channel的size为0,如果接收不到数据,会一直阻塞在这里,直到可以接收数据为止
fmt.Println(<-c)
}
死锁
第一种情况
func demo2() {
c := make(chan int,0)
fmt.Println(<-c) //一直接受不到数据,阻塞在这里,死锁
}
第二种情况
func demo3() {
c := make(chan int,0)
c <- 1
fmt.Println(<-c)
}
这是因为channel size为0,之前把1传进c中,但是没有接收方,等到<-c
时,已经接收不到数据传入channel,所以死锁
第三种情况
//var只定义了类型,但并未初始化,deadlock
func demo4() {
var c chan int
go func() {
c <- 1
}()
fmt.Println( <-c )
}
第四种情况
func demo5() {
var c chan int //定义类型
c = make(chan int ,0) //初始化
go func() {
for i := 0; i < 3; i++ {
c <- i //传入channel数据
}
}()
for v := range c{
fmt.Println(v)
}
}
//结果是死锁,应该将数据传进channel后,并没有关闭channel,for循环接收channel一直在监听,死锁
数据传进channel后,输入方主动关闭channel
func demo5() {
var c chan int
c = make(chan int ,0)
go func() {
for i := 0; i < 3; i++ {
c <- i
}
close(c) //或者defer close(c)
}()
for v := range c{
fmt.Println(v)
}
}
当channel 关闭且缓冲区为0时
func demo6() {
c := make(chan int,1)
close(c)
fmt.Println(<-c)
}
//输出为0
关闭未初始化的channel,会panic
func demo6() {
var c chan int
close(c)
}
一些特殊情况
func main() {
var ch chan int
//func1
go func() {
ch = make(chan int, 1)
ch <- 1
}()
//func2
go func(ch chan int) {
time.Sleep(time.Second)
<-ch
}(ch)
c := time.Tick(1 * time.Second)
for range c {
fmt.Printf("#goroutines: %d\n", runtime.NumGoroutine())
}
}
//一段时间后输出结果为#goroutines: 2
先给出结论,运行的goroutines分别为func2和主函数,造成这个问题的主要原因是因为ch只定义了类型,但并未初始化,但func1中,将ch初始化了,并且传输数据到ch中了,所以func1并未阻塞。
那可能会有疑问,既然func1中将ch初始化了,并且func2先睡眠了一秒再从ch接收数据,并且ch的缓存为1,不存在阻塞,那么为什么func2阻塞了呢?
因为func2是一个闭包函数,所以func2的其实一直都是只定义未初始化的channel,他并未受func1中初始化的影响,所以会一直阻塞,大坑==
几个需要注意的点:
- channel关闭后,再向channel中写入数据会panic
- channel关闭后,再次关闭channel,会panic
- 关闭未初始化的channel,会panic
- channel关闭后,可以继续从channel中接收数据
- 当channel 关闭且缓冲区为0时,继续从channel接收数据会接收到一个channel定义类型的零值
- channel先进先出