概述
go channel 存在3种状态
- nil 未初始化的状态,只进行了声明
- active 正常的channel,可读或者可写
- closed 已关闭,关闭后的channel != nil
有种特殊情况,当nil的通道在select的某个case中时,这个case会阻塞,但不会造成死锁。
for...range
不断从channel中读取数据,for...range
可以自动识别close掉的channel
func main() {
c := make(chan int, 3)
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
for x := range c {
fmt.Println(x)
}
}()
go func() {
defer wg.Done()
for i := 4; i > 0; i-- {
c <- i
}
close(c)
fmt.Println(c == nil)
}()
wg.Wait()
}
// output
4
3
2
1
false
_, ok
对于已关闭的channel进行读取,会得到零值,这样会造成读取到的假象,通过_, ok
可以判断是否从channel中读取到数据
func main() {
c := make(chan bool, 3)
close(c)
x, ok := <- c
fmt.Println(x, ok)
}
// output
false false
select
select
可同时监控多路channel,并处理最先发生的channel
var wg sync.WaitGroup
func main() {
c := make(chan int, 2)
d := make(chan string, 2)
wg.Add(1)
go func() {
defer wg.Done()
d<-"joker"
c<-1
}()
select {
case x := <-c:
fmt.Println(x)
case y := <-d:
fmt.Println(y)
}
wg.Wait()
}
// output
joker
只读/只写channel
只读channel只能读取,只写channel只能写入,更易读,更安全
func main() {
c := make(chan int, 2)
cw := (chan<- int)(c)
cr := (<-chan int)(c)
cw <- 1
cw <- 2
fmt.Println(<-cr,<-cr)
}
// output
1 2
无阻塞读写channel
通过select和time.After配合读写无阻塞
func main() {
c := make(chan interface{})
v, ok := unBlockRead(c)
fmt.Println(v, ok)
ok = unBlockWrite(c, "joker")
fmt.Println(ok)
}
func unBlockWrite(c chan<- interface{}, v interface{}) (ok bool) {
select {
case c<-v:
return true
case <-time.After(time.Second):
return false
}
}
func unBlockRead(c <-chan interface{}) (v interface{}, ok bool) {
select {
case v, ok = <-c:
return
case <-time.After(time.Second):
return nil, false
}
}
// output
<nil> false
false
网友评论