channel的类型
我不认为是否有缓冲区可以作为 channel 分类的依据,所谓的无缓冲的channel,就是容量为0 的channel
//所谓无缓冲的channel
c:= make(chan int) //等价于 c:= make(chan int,0)
//创建有缓冲的channel
c:= make(chan int,3)
真正的类型划分为三种:
//对列类型chan 可存可取 先进先出
var queneChan chan int
//只存类型chan 只存不取
var inChan chan<- int
//只取类型chan 只取不存
var outChan <-chan int
channel 操作引起阻塞的情况
简单来说就两句话
存而不进
容量为0 肯定存不进
//无缓冲
package main
func main() {
c := make(chan int, 0)
c <- 1
}
//fatal error: all goroutines are asleep - deadlock!
增加容量即可
package main
func main() {
c := make(chan int, 1)
c <- 1
}
// Process finished with the exit code 0
取而不得
与上面同理,通道中没有数据的时候,取数据,肯定取不到
package main
func main() {
c := make(chan int, 0)
<-c
}
//fatal error: all goroutines are asleep - deadlock!
有容量没数据一样取不到
package main
func main() {
c := make(chan int, 1)
<-c
}
//fatal error: all goroutines are asleep - deadlock!
有数据能取,则不会阻塞
package main
import "fmt"
func main() {
c := make(chan int, 1)
c <- 100
fmt.Println(<-c)
}
// 100
// Process finished with the exit code 0
操作channel 的内置函数
make()
make为引用类型初始化内存空间,用户 slice、map 、chan
他们三个的共同点是他们都是引用类型的,且都需要分配容量
package main
import "fmt"
func main() {
var c = make(chan int)
var c1 chan int
fmt.Println("c:", c, "c1:", c1)
}
//c: 0xc000086120 c1: <nil>
len() & cap()
len() 返回引用类型变量中数据的个数
cap() 返回引用类型变量的容量的大小
数据的个数≤ 容量
package main
import "fmt"
func main() {
var c = make(chan int, 3)
fmt.Println("初始:")
fmt.Printf("len(c)=%d cap(c)=%d\n", len(c), cap(c))
c <- 1
c <- 2
fmt.Println("存了两个以后:")
fmt.Printf("len(c)=%d cap(c)=%d\n", len(c), cap(c))
<-c
fmt.Println("取出一个以后:")
fmt.Printf("len(c)=%d cap(c)=%d\n", len(c), cap(c))
}
初始:
len(c)=0 cap(c)=3
存了两个以后:
len(c)=2 cap(c)=3
取出一个以后:
len(c)=1 cap(c)=3
Process finished with the exit code 0
可以发现len()随存取数据变化,而cap 一直没有变化
close() --重要
先来看官方定义
// The close built-in function closes a channel, which must be either
// bidirectional or send-only. It should be executed only by the sender,
// never the receiver, and has the effect of shutting down the channel after
// the last sent value is received. After the last value has been received
// from a closed channel c, any receive from c will succeed without
// blocking, returning the zero value for the channel element. The form
//
// x, ok := <-c
//
// will also set ok to false for a closed and empty channel.
func close(c chan<- Type)
注意看close 方法参数接受的类型 chan<- 说明可以接受的类型是chan<- 和 chan
注: chan、chan<- 、<-chan 三种类型的关系是 chan = <-chan ∩ chan<-, (∩–交集)
所以close()只能影响可以存数据的channel
1、影响 chan<- (只存channel)
被关闭的channel,不能存数据
package main
func main() {
c := make(chan<- int, 10)
close(c)
c <- 20
}
//panic: send on closed channel
2、影响 chan (只取channel)
刚才说了对 存的影响 ,现在来看取的影响:
从已关闭的channel中取数据不会引起阻塞,与chaneel 的容量,channel中有无数据都没有关系
x,ok := <-c
如果c中有数据 x 是正常取得的数据,ok 是 true
如过c中没有数据 x 是对应类型的零值,ok 是 false
package main
import "fmt"
func main() {
//无容量
c := make(chan int)
close(c)
v, ok := <-c
fmt.Println(v, ok) //0,false
//有容量
c1 := make(chan int, 10)
c1 <- 20
c1 <- 10
close(c1)
for v1, ok1 := <-c1; ok1; v1, ok1 = <-c1 {
fmt.Println(v1, ok1)
}
//20,true
//10,true
}
形如 x,ok := <-c 何时返回false 官方的解释是:
The form
x, ok := <-c
will also set ok to false for a closed and empty channel.
意思是ok 为false 的条件是:被关闭的channel& 空的channel(缓冲区中无数据),二者缺一不可