Go并发编程之Select(4)

Admin 2022-05-20 21:33:17 GoLang

Go的select功能和C中的select, poll, epoll类似,就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。

在某些场景下,我们需要同时从多个通道接收数据。通道在接收数据时,如果没有数据可以接收将会发生阻塞。

使用 select 类似于 switch 语句,每个case会对应一个通道的通信(接收或发送)过程,但是它的 case 涉及到 channel 有关的 I/O 操作或者说 select 就是用来监听和 channel 有关的 IO 操作,当 IO 操作发生时,触发相应的动作。

// 基本用法
select {
    case <- ch1:
    // 如果ch1成功读到数据,则进行该case处理语句
    case ch2 <- 1:
    // 如果成功向ch2写入数据,则进行该case处理语句
    default:
    // 如果上面都没有成功,则进入default处理流程
}

案例1:

package main

import "fmt"

func main() {
    c, quit := make(chan int), make(chan int)
    go func() {
        c <- 2  // 添加数据
        quit <- 1 // 发送完成信号
    } ()
    
    for isQuit := false; !isQuit; {
        // 监视信道c的数据流出
        select { 
            case v := <-c: fmt.Printf("received %d from c", v)
            case <-quit: isQuit = true 
            // quit信道有输出,关闭for循环
        }
    }
}

案例2:

实现timeout机制

package main

import (
    "fmt"
    "time"
)

func main()  {
    timeOut := make(chan int)
    ch := make(chan int)
    
    go func() {
        time.Sleep(1e9)
   
        timeOut <- 1

    }()
    
    select {
    case <-ch:
        fmt.Println("c is ")
    case a := <-timeOut:
        fmt.Println("timeout", a)
    }
}

同时等待读取ch和timeOut,当超时时间有数据时候,<- timeout会执行,即 select 语句会退出。 而不是一直阻塞在 ch 的读取操作上。 从而实现了对 ch 读取操作的超时设置。

如果select包含default,则上述两个都无法成功读取的情况下,直接进入default。

案例3:

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan int)

    go s1(ch1)

    for {
        select {
        case c1 := <- ch1:
            fmt.Println("c1 is", c1)
        case <- time.After(time.Second * 2):
            fmt.Println("timeout: 2s")
            return
        }

    }
}

func s1(ch chan int) {
    for i:=0; i<100; i++ {
        ch <- i

        time.Sleep(3 * time.Second)
    }
}

switch和select区别:

  1. select可处理一个或多个channel的发送/接收操作。

  2. 如果多个case同时满足,select会随机选择一个。

  3. 对于没有case的select,会一直等待,可用于阻塞main函数。

  4. switch可以是各种类型,select 只能是IO操作(通常是channel)。

  5. switch是顺序执行的。

  6. switch中的default是默认的意思,当所有case不满足的时候,就会执行default。

  7. select中的default是当select发现没有case满足,要block时的选择。

相关文章
最新推荐