select的作用:
go可以监听channel上的数据流动
select用法类似switch,但是select的每个case语句里必须是一个IO操作
在一个select语句中,Go语言会按顺序从头至尾评估每一个发送和接收的语句。
如果其中的任意一语句可以继续执行(即没有被阻塞),那么就从那些可以执行的语句中任意选择一条来使用。
如果没有任意一条语句可以执行(即所有的通道都被阻塞),那么有两种可能的情况:
如果给出了default语句,那么就会执行default语句,同时程序的执行会从select语句后的语句中恢复。
如果没有default语句,那么select语句将被阻塞,直到至少有一个通信可以进行下去。
下面给出一个代码展示select的使用例子
func main(){
ch :=make(chan int) //用来进行数据通信的channel
quit := make(chan bool) //用来判断是否退出的channel
go func() {
for i:=0;i<5;i++{
ch <- i
time.Sleep(time.Second)
}
close(ch)
quit<- true //通知字主go退出
runtime.Goexit() //
}()
for {
select { //select内部是不带有监听的,如果任何一条语句都不能执行,那么会一直阻塞在,除非有default语句
case num := <-ch:
fmt.Println("读到:",num)
case <-quit:
fmt.Println("收到退出信号")
//break //break跳出select
//runtime.Goexit()
return //终止进程
}
fmt.Println("================")
}
}
下面给出一个案例:用select实现fibonacci数列:
1 1 2 3 5 8 13 21 34 55 89
x,y = y,x+y
func fibonacci(ch <-chan int,quit <-chan bool){
for {
select {
case num:= <-ch:
fmt.Print(num," ")
case <-quit:
return
}
}
}
func main(){
ch := make(chan int)
quit := make(chan bool)
go fibonacci(ch, quit) //子go程,打印fibonacci数列
x,y := 1,1
for i:=0;i<20;i++{
ch<- x
x,y=y,x+y
}
quit<- true
}
死锁 : 不是一种锁,而是一种错误使用锁导致的现象
1.单go程自己死锁
channel应该在至少2个以上的go程中进行通信,否则死锁
2.go程间channel访问顺序导致死锁
使用channel一端读(写),要博阿正另一端写(读),同时有机会执行,否则死锁
3.多go程,多channel交叉导致死锁
A go程,掌握M的同时,尝试拿N;B go程,掌握N的同时尝试拿M
2,3类型死锁的例子
func main11(){
ch:= make(chan int)
go func() {
ch<- 789
}()
num:= <- ch
fmt.Println("num = ",num)
}
func main(){
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
for {
select {
case num:=<- ch1:
ch2 <- num
}
}
}()
for {
select {
case num:= <-ch2:
ch1<-num
}
}
}