golang的chan翻译成中文就是管道,顾名思义,就是管道的一端用来读,另一端用来写,这与write和read函数的性质是非常相似的,比如说管道中没数据,就会发生读阻塞
,管道中数据是满的,就会发生写阻塞
。又类似生产者和消费者,也就是必须有生产(写),才能消费(读)
chan是用来进行go程间通信的,chan的相关操作有发送、接收、关闭,管道是一种引用类型
len函数可以获取通道内元素的数量,cap函数获取通道的容量
注意:
- 写和读一般放在2个go程,否则容易死锁
- 如果阻塞发生在主go程,并且没有其他goroutine在运行,会导致程序挂掉
- 当管道中的数据读完后,再继续读,存在以下两种情况
- 通道已经close,则读出的是通道内类型的零值
- 通道未close,会发生阻塞
管道的遍历的两种方式如下:
func recvChan(ch <-chan int) {
for val := range ch {
fmt.Println(val)
}
}
func main() {
var ch chan int
ch = make(chan int, 2)
ch <- 0
ch <- 4
close(ch)
go recvChan(ch)
time.Sleep(time.Second * 6)
}
或者
func recvChan(ch <-chan int) {
for {
val,ok := <-ch
if !ok {
break
}
fmt.Println(val)
}
}
func main() {
var ch chan int
ch = make(chan int, 2)
ch <- 0
ch <- 4
close(ch)
go recvChan(ch)
time.Sleep(time.Second * 6)
}
无缓冲通道
无缓冲通道,即通道的容量为0,如果在主go程中写,必须先开启读go程,才能不挂掉;
如果在非主go程中写,则会阻塞,程序不会崩
<- 和 ->的所有作用
- 表示类型,
var ch chan int
普通通道,var ch <-chan int
只读通道,var ch chan<- int
只写通道 - 表示运算符,
ch <- 3
,向ch通道发送数据(写),<-ch
或val := <-ch
从ch通道中接收数据(读)
应用示例:
监控标准输入的值,将其写入管道,然后将管道返回,供用户调用。
package main
import "fmt"
type ChanMsg struct {
c chan string
}
func NewChanMsg() *ChanMsg {
return &ChanMsg{c: make(chan string)}
}
func (cs *ChanMsg) Consume() <-chan string{
go func() {
for {
var i string
_, _ = fmt.Scanln(&i)
cs.Gen(i)
}
}()
return cs.c
}
func (cs *ChanMsg) Gen(i string) {
cs.c <- i
}
func main() {
cs := NewChanMsg()
c := cs.Consume()
for val := range c {
fmt.Println(val)
}
}
chan优雅的关闭
/go/channel/ru-he-you-ya-di-guan-bi-channel