golang channel 分为有缓冲与无缓冲两种类型,最大的区别是阻塞问题。
c1:=make(chan int) 无缓冲,channel在读和写是都会阻塞
c2:=make(chan int,10) 有缓冲
Go Channel的基本操作语法如下:
c := make(chan bool) //创建一个无缓冲的bool型Channel
c <- x //向一个Channel发送一个值
<- c //从一个Channel中接收一个值
x = <- c //从Channel c接收一个值并将其存储到x中
x, ok = <- c //从Channel接收一个值,如果channel关闭了或没有数据,那么ok将被置为false
不带缓冲的Channel兼具通信和同步两种特性,颇受青睐。
close():
close主要用来关闭channel通道其用法为close(channel),并且只在生产者的地方关闭channel,而不是在消费者的地方关闭.并且关闭channel后,便不可再向channel中继续存入数据,但是可以继续从channel中读取数据.从一个已关闭的channel中读数据,不会panic,会读到channel对应类型的0值,比如int为0, bool 就为false,但是这样无法确定读取到的是否是正确的数据,所以一般会使用channel返回的第二个可选参数来判断channel是否关闭。
chan <- struct {}{} (常用)
语义为将一个空数据传递给channel.因为struct{}{}占用的内存非常小,而且我们对数据内容也不关心,通常用来做信号量来处理.
for循环读取channel:
for i := range ch { // ch关闭时,for循环会自动结束
println(i)
}
范例1:等待一个事件,通过close一个Channel实现
import “fmt”
func main() {
fmt.Println(“Begin doing something!”)
c := make(chan bool)
go func() {
fmt.Println(“Doing something…”)
close(c) //换成 c <-true 更好理解
}()
<-c //栅栏,等同读到false
fmt.Println(“Done!”)
}
这里main goroutine通过”<-c”来等待sub goroutine中的“完成事件”,sub goroutine通过close channel促发这一事件。
结果:
Begin doing something!
Doing something…
Done!
范例2:close channel还可以用于协同多个Goroutines
import “fmt”
func worker(start chan bool, index int) {
<-start
fmt.Println(“This is Worker:”, index)
}
func main() {
start := make(chan bool)
for i := 1; i <= 100; i++ {
go worker(start, i)
}
close(start)
select {} //deadlock we expected
}
select:
要从多个channel读取数据,需要配合select关键词使用。
在go中使用select – case 可以在多个channel上监听读写事件,某个case产生了读写事件时,则执行相应case中的代码。
select{
case :
/*…*/
default:
/*…*/
}
如果有default case的话,其他case没收到消息的话,会马上走default case,然后整个select语句结束.
范例3:
import (
“fmt”
“time”
)
func main() {
c := make(chan int)
o := make(chan bool)
go func() {
for {
select {
case i := <-c:
fmt.Println(i)
case <-time.After(time.Duration(3) * time.Second): //设置超时时间为3s,如果channel 3s钟没有响应,一直阻塞,则报告超时,进行超时处理.
fmt.Println(“timeout”)
o <- true
break
}
}
}()
<-o
}
结果:
timeout
for … select
LOOP:
for{
select{
case ….:
break LOOP //@A 跳到标志位
}
}
注意上面@A的地方
两个重要的使用方式:
1、超时机制Timeout
带超时机制的select是常规的tip,下面是示例代码,实现30s的超时select:
func worker(start chan bool) {
timeout := time.After(30 * time.Second) //说明time.After()的返回值是一个 chan 类型。
for {
select {
// … do some stuff
case <- timeout:
return
}
}
}
2、心跳HeartBeart
与timeout实现类似,下面是一个简单的心跳select实现:
func worker(start chan bool) {
heartbeat := time.Tick(30 * time.Second)
for {
select {
// … do some stuff
case <- heartbeat:
//… do heartbeat stuff
}
}
}
技术关键字推荐:golang 编程 技术 channel time