select是Go中的一个控制结构,类似于switch语句,用于处理异步IO操作。select会监听case语句中channel的读写操作,当case中channel读写操作为非阻塞状态(即能读写)时,将会触发相应的动作。
func main(){
c1 := make(chan string)
c2 := make(chan string)
go func(){
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func(){
time.Sleep( 2 * time.Second)
c2 <- "two"
}()
for i:= 0; i < 2; i++ {
select {
case msg1 := <- c1:
fmt.Println("received",msg1)
case msg2 := <- c2:
fmt.Println("received",msg2)
}
}
}
func main(){
var c1, c2 chan int
n1 := <- c1
n2 := <- c2
}
我们创建两个 channel,然后想同时从 c1, c2 来接受数据,然后看 c1, c2 谁发送数据快,谁就先接受谁的数据。
func main(){
var c1, c2 chan int
select {
case n := <- c1:
fmt.Println("Received from c1:",n)
case n := <- c2:
fmt.Println("Received from c2:",n)
default:
fmt.Println("No value")
}
}
我们用 select 来实现上面我们想要效果,不过现在 c1, c2 都是 nil,所以就会走到 default 分支。其实这就是在 channel 里面做了一个非阻塞的处理。在学习我们已经了解到 channel 无论是发数据还是数据都会互相阻塞。
如果去掉 default 就会 deadlock
,因为没有人发数据所以就造成了 deadlock
。
func generator() chan int {
out := make(chan int)
go func(){
i := 0
for{
time.Sleep(
time.Duration(rand.Intn(1500)) * time.Millisecond)
out <- i
i++
}
}()
return out;
}
func main(){
var c1, c2 = generator(),generator()
select {
case n := <- c1:
fmt.Println("Received from c1:",n)
case n := <- c2:
fmt.Println("Received from c2:",n)
}
}
func worker(id int, c chan int){
for n := range c{
fmt.Printf("Workder %d received %d\n", id, n)
}
}
func createWorker(id int) chan<- int {
c := make(chan int)
go worker(id, c)
return c
}
func generator() chan int {
out := make(chan int)
go func(){
i := 0
for{
fmt.Println("generator")
time.Sleep(
time.Duration(rand.Intn(1500)) * time.Millisecond)
out <- i
i++
}
}()
return out;
}
func main(){
var c1, c2 = generator(),generator()
var worker = createWorker(0)
n := 0
hasValue := false
for {
var activeWorker chan<- int
if hasValue {
activeWorker = worker
}
select {
case n = <- c1:
hasValue = true
case n = <- c2:
hasValue = true
case activeWorker <- n:
hasValue = false
}
}
}
- 设置 n = 0,创建一个激活的 activeWorker 为 chan int 类型默认值为 nil 所以会跳过这个。
有疑问加站长微信联系(非本文作者)