channel的创建和关闭:
ch:=make(chan int) ,初始化一个int类型的channel
使用Go内置函数close来关闭一个channel, close(ch)
注意:
1.向一个已经关闭的channel发送消息会程序会panic
2.关闭一个未初始化的channel会panic
3.可以从一个已经关闭的channel中读取消息,能够读取channel中未被读取的消息,如果所有消息均被读出,则会读到类型的零值。从一个已经关闭的channel中读取消息永远不会阻塞,ok,idiom:=<-ch, 如果ok为真则未关闭,false则已经关闭。
4.channel关闭时候,所有的goroutine都会受到消息
无缓存的channel
从无缓存的channel中读取消息会阻塞,直到有goroutine向此channel中发送消息,向无缓存的channel中发消息也会阻塞,直到有goroutine向该channel中读取消息。
实例代码:
//读数据
var ch chan int
ch = make(chan int)
//close(ch)
go func() {
fmt.Println("A")
_ = <-ch //阻塞在这里,不会打印B
fmt.Println("B")
}()
time.Sleep(time.Second * time.Duration(5))
//存数据
var ch chan int
ch = make(chan int)
//close(ch)
go func() {
fmt.Println("A")
ch <- 8 //阻塞在这里,不会打印B
fmt.Println("B")
}()
有缓存的channel
有缓存的 channel 类似一个阻塞队列(采用环形数组实现)。当缓存未满时,向 channel 中发送消息时不会阻塞,当缓存满时,发送操作将被阻塞,直到有其他 goroutine 从中读取消息;相应的,当 channel 中消息不为空时,读取消息不会出现阻塞,当 channel 为空时,读取操作会造成阻塞,直到有 goroutine 向 channel 中写入消息
make函数的第二个参数来指定缓存的容量
实例代码:
var ch chan int
ch = make(chan int,1)
//close(ch)
go func() {
fmt.Println("A")
_ = <-ch //阻塞,尽管有缓存,但是channel是空的没有放入消息
fmt.Println(”B”)
_ = <-ch //阻塞,不会打印C
fmt.Println("C")
}()
time.Sleep(time.Second * time.Duration(5))
channel的遍历
注意:channel可以用range取值,并且一直会从channel中取值,直到有goroutine把channel关闭循环才会结束。
示例代码:
var ch chan int
ch = make(chan int, 0)
go func() {
for v := range ch { //循环直到有goroutine close(ch)
fmt.Println(v)
}
}()
ch <- 1
ch <- 2
ch <- 3
time.Sleep(time.Second * 5) //睡眠5
ch <- 4
ch <- 5
close(ch)
输出:12345,其中45是在main函数睡眠5秒后输出,range一直在持续,直到close(ch)
也可以使用 :
for {
c, ok := <-ch
if !ok {
break
}
}
这种方式来遍历。
select和channel的配合使用
注意:
1.select可以同时监听多个channel的写入或读取
2.执行select若只有一个case不阻塞,则执行这个case块
3.若多个case不阻塞,则随机挑选一个执行
4.若所有case都阻塞则实行default块,若未定义default则select语句阻塞
直到有case被唤醒
5.使用break跳出select
示例代码:
ch1 := make(chan int)
ch2 := make(chan int)
ch3 := make(chan int)
ch4 := make(chan int)
select {
case <-ch1:
fmt.Println("A")
case <-ch2:
fmt.Println("B")
case <-ch3:
fmt.Println("C")
case <-ch4:
fmt.Println("D")
default:
fmt.Println("E") //全部阻塞,执行default
}
fmt.Println("F")
示例代码2:
ch1 := make(chan int)
ch2 := make(chan int)
ch3 := make(chan int)
ch4 := make(chan int)
go func() {
fmt.Println("1")
ch1 <- 1
fmt.Println("2")
ch2 <- 2
fmt.Println("3")
ch3 <- 3
}()
time.Sleep(time.Second * 1)
select {
case <-ch1:
fmt.Println("A")
case <-ch2:
fmt.Println("B")
case <-ch3:
fmt.Println("C")
case <-ch4:
fmt.Println("D")
default:
//fmt.Println("E") //全部阻塞,执行default
}
fmt.Println("F")
//输出: 1
// A
// F
// 2
首先执行goroutine 会打印1 此时给ch1赋值 会阻塞,1秒后当执行select 则case ch1通过打印A,此时 goroutine 被唤醒 同时main函数也会继续执行 则打印F、2,main函数退出 .