Go 中的 channel 是 goroutine 之间的通信机制。
Go 实现并发的方式是:“不是通过共享内存通信,而是通过通信共享内存。” 当你需要将值从一个 goroutine 发送到另一个 goroutine 时,将使用 channel。
创建channel
创建 channel,需使用内置的 make() 函数,如下所示:
c1 := make(chan string) //无缓存channel
c2 := make(chan int, 1) //有缓冲
无缓冲: 不仅仅是向 c1 通道放 1,而是一直要等有别的携程 <-c1 接手了这个参数,那么c1<-1才会继续下去,要不然就一直阻塞着。
有缓冲: c2<-1 则不会阻塞,因为缓冲大小是1(其实是缓冲大小为0),只有当放第二个值的时候,第一个还没被人拿走,这时候才会阻塞。
一个 channel 可以执行两项操作:发送数据和接收数据。
ch <- x // sends (or write) x through channel ch
x = <-ch // x receives (or reads) data sent to the channel ch
<-ch // receives data, but the result is discarded
关闭channel
可在 channel 中执行的另一项操作是关闭 channel。
若要关闭 channel,需使用内置的 close() 函数,如下所示:
close(ch)
//若是定义了通道的变量,但是没有通过make函数进行初始化
//使用了close函数,就会报错:panic: close of nil channel
for循环读取channel
for i := range ch { // ch关闭时,for循环会自动结束
fmt.println(i)
}
防止读取超时channel
select {
case <- time.After(time.Second*2):
fmt.println("read channel timeout")
case i := <- ch:
fmt.println(i)
}
防止写入超时channel
select {
case <- time.After(time.Second *2):
println("write channel timeout")
case ch <- "hello":
println("write ok")
}
channel 的 size 最好是 1 或者是 unbuffered
在使⽤用 channel 的时候,最好将 size 设置为 1 或者使⽤用 unbuffered channel。
其他 size 的 channel往往都会引⼊入更更多的复杂度,需要更更多考虑上下游的设计。
举例说明:
1.初始化
ExpireSignal = make(chan int, 1)
2.更新channel
//在需要处调用
func (p *StreamPool) updateExpireSignal(signal int) {
ExpireSignal <- signal //ExpireSignal中写入signal
}
3.读取channel,进行处理
//常驻监听ExpireSignal信号
func DealExpireSignal() {
go func() {
for {
select {
case ch := <-ExpireSignal: //监听超时信号
//0-默认值
//1-命令行
if ch == 1 {
//根据超时信号处理
fmt.Println("ExpireSignal:", ch)
ExpireSignal <- 0
}
}
}
}()
}