1、单向channel
单向channel只能用于发送或者接收数据。因为channel可以通过参数传递,所谓的单向channel只是对channel的一种使用限制:
- func readChan(chanName <- chan int):只能读数据
- func writeChan(chanName chan<- int):只能写数据
func TestChannel(t *testing.T) {
writeChan(channel)
readChan(channel)
}
//单向channel
func readChan(chanName <-chan int) {
msg, ok := <-chanName
fmt.Println(msg, " 1--- ", ok) // 1,true
msg, ok = <-chanName
fmt.Println(msg, " 2--- ", ok) //0,false
}
func writeChan(chanName chan<- int) {
chanName <- 1
close(chanName)
//panic
close(chanName)
}
2、select
使用select可以监控多个channel,当有channel中有数据到达时,就从中读取数据。
//select
func addNumberToChan(chanName chan int) {
for {
chanName <- 1
//time.Sleep(1 * time.Second)
}
}
func TestSelect(t *testing.T){
var chan1 = make(chan int, 10)
var chan2 = make(chan int, 10)
go addNumberToChan(chan1)
go addNumberToChan(chan2)
for {
select {
case e := <-chan1:
fmt.Println("chan1 -->", e)
case e := <-chan2:
fmt.Println("chan2-->", e)
default:
fmt.Println("default")
time.Sleep(1 * time.Second)
}
}
}
select语句的多个case的执行顺序是随机的。
select的case语句读channel不会阻塞,尽管channel中没有数据,这是由于case语句编译后调用读channel时会传入不阻塞的channel,此时读取不到数据不会将该goroutine加入等待队列,而是直接走default返回。
3、range
通过range可以持续从channel中读取数据,就像在遍历一个数组一样,当channel中没有数据时,当前goroutine就会被阻塞。
//range
func changeRange(chanName chan int) {
for e := range chanName {
time.Sleep(1 * time.Second)
fmt.Println("get element", e)
}
}
如果向此channel写数据的goroutine退出时,系统检测到这种异常就会panic,否则range将会永远阻塞。