channel直译过来就是管道,chan关键字定义了goroutine中的管道通信,一个goroutine可以和另一个goroutine进行通信。
chan的读写和定义如下:
//define a chan type variable
var ch chan int = make(chan int, 10);
//or
ch := make(chan int, 10);
//write data into chan
ch <- 1;
ch <- 2;
//read data from chan
var x int;
x = <-ch;
x = <-ch;
看下面这段代码,其中x获取ch队头值,nonempty返回ch是否非空的:
func main() {
var ch chan int = make(chan int, 10)
ch <- 1
ch <- 2
ch <- 3
close(ch)
var x int
var nonempty bool
x, nonempty = <-ch
fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
}
打印结果:
可以看到chan是类似队列的先进先出类型,每次读出一个数据后,ch自动弹出该数据不再保存。
chan一定要初始化才能进行读写操作,否则产生死锁:
package main
import (
"fmt"
)
func main() {
var ch chan int// = make(chan int, 10)
ch <- 1
ch <- 2
ch <- 3
close(ch)
var x int
var nonempty bool
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
}
执行结果,由于所有goroutine已经睡眠,产生死锁:
select会执行第一个可以执行的case语句,会一直监听直到有第一个可以执行的语句。或者换一种说法,select就是用来监听和channel有关的IO操作,当 IO 操作发生时,触发相应的动作。
看这段代码:
package main
import (
"fmt"
"time"
)
func main() {
var ch chan int = make(chan int, 10)
var x int = 0
var nonempty bool
go func() {
ch <- 1
ch <- 2
ch <- 3
close(ch)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
}()
select {
case ch <- x:
fmt.Println("ch write", x)
case x = <-ch:
fmt.Println("ch read", x)
default:
fmt.Println("nothing to do")
}
time.Sleep(time.Second)
}
执行结果,写入0:
注释掉第一个case:
select {
// case ch <- x:
// fmt.Println("ch write", x)
case x = <-ch:
fmt.Println("ch read", x)
default:
fmt.Println("nothing to do")
}
执行结果,由于ch为空无法读出,运行default:
如果有多个io操作都可以执行的话,select会随机选择一个执行:
select {
// case ch <- x:
// fmt.Println("ch write", x)
case ch <- 4:
fmt.Println("ch write 4")
case ch <- 5:
fmt.Println("ch write 5")
case x = <-ch:
fmt.Println("ch read", x)
default:
fmt.Println("nothing to do")
}
两种结果: