channel
是连接多个gotoutine
的管道。可以从一个Go协程将值发送到管道,在别的Go协程中接收。
创建channel
的语法是:
make(chan val-type)
make
函数对于channel描述是:使用指定的缓冲区容量来初始化通道的缓冲区。
chan
是关键字,代表channel
。
val-type
是类型,代表通道接受什么类型的数据。
<-
是通道操作符,指数据流的方向。使用channel<-
来发送一个新的值到通道中。使用<-channel
从通道中接收一个新的数据。
messages <- msg
//messages是通道名,将msg发送到通道messages中
msg <- messages
//用msg来接收从通道messages中传来的数据
定义一个通道来传输数据,用一个变量来接收传输的数据。
func main(){
//定义一个channel通道
messages := make(chan string)
//将一个函数放在协程中运行,并用通道传输数据
go func() {messages <- "ping"}()
//接收通道传输的信息
msg := <-messages
fmt.Println(msg)
}
//ping
通过实例,可以看出消息“ping”
,通过通道从一个Go协程发送到另一个中。
默认情况下,发送和接受操作在另一端准备好之前都会堵塞。
func sum(s []int,c chan int){
sum := 0
for _,v := range s{
sum += v
}
c <- sum //将和送入C
}
func main(){
s := []int{7,2,4,5,8,1}
c := make(chan int)
go sum(s[:len(s)/2],c)
go sum(s[len(s)/2:],c)
x,y := <-c,<-c //x,y从C中接受数据
fmt.Println(x,y,x+y)
}
在创建通道时,默认是无缓冲的。因此,只有在对应的接收通道准备好接收时,才允许进行发送。
可缓冲通道允许在没有对应接收方的情况下,缓存限定数量的值。
在通道有缓冲区时,没有对应的并发接收方也能保证通道的运行。
func main(){
//定义一个channel,设置缓冲区为2
messages := make(chan string,2)
//通过goroutine传递信息
//go func() {messages <- "ping"}()
messages <- "buffered"
messages <- "channel"
//接收通道传输的信息
msg := <-messages
fmt.Println(msg)
//直接输出通道接收的数据
fmt.Println(<-messages)
}
//buffered
//channel
使用通道来同步Go协程间的执行状态。
func worker(done chan bool){
fmt.Println("working")
//模拟阻塞
time.Sleep(time.Second)
fmt.Println("done")
done <- true
}
这是一个将在Go协程中执行的函数,done通道将被用于通知其他Go协程这个函数已经工作完毕。发送true
表示通道已经运行完毕。
func main(){
done := make(chan bool,1)
go worker(done)
<-done
}
程序将在接收到通道中worker发出的通知前一直阻塞。
当使用通道作为函数参数时,可以指定这个通道是不是只用来发送或者接收值。
使用通道作为参数,可以根据数据流的方向,只允许发送chan<-
或者接收<-chan
作为参数。
定义一个ping()
函数,参数是只允许发送数据的通道。
func ping(pings chan<- string,msg string){
pings <- msg
}
定义一个pong()
函数,参数可以用来接收数据,也可以用来发送数据。
func pong(pings <-chan string,pongs chan<- string){
msg := <-pings
pongs <- msg
}
经过主函数的调用,将输出数据经过ping()
函数,传输到通道pings
中,由于ping()
函数不能用来接收数据,但是输出数据还存在通道中,那么调用pong()
函数,获取通道pings
中的数据,再传到通道pongs
中,再输出。
func main(){
pings := make(chan string,1)
pongs := make(chan string,1)
//调用ping函数发送数据到msg中
ping(pings,"passed message")
//调用pong函数
pong(pings,pongs)
fmt.Println(<-pongs)
}
//passed message
Go语言中的通道选择器可以同时等待多个通道操作。
通道选择器select
的语法为:
select{
case handle1 :
statement
case handle2 :
statement
}
//handle1和handle2是在case中做的处理或者判断
//statement是在符合条件后需要执行何种语句
定义两个通道,将通道中的值输出。
func main(){
c1 := make(chan string)
c2 := make(chan string)
go func(){
//通过时间来模拟阻塞
time.Sleep(time.Second * 4)
c1 <- "one"
}()
go func() {
//通过时间来模拟阻塞
time.Sleep(time.Second * 1)
c2 <- "two"
}()
for i:=0;i<2;i++{
//选择通道的运行
select {
case msg1 := <-c1:
fmt.Println("received",msg1)
case msg2 := <-c2:
fmt.Println("received",msg2)
}
}
}
//received two
//received one
通过例子可以看出,选择器在并行的协程中,会选择优先解除阻塞的协程运行。