Go——处理用户连接超时

所谓超时,就是一段时间用户没有做出任何操作,这里需要了解 select

select

  • select 用法与 switch 语言非常类似,由 select 开始一个新的选择块,每个选择条件由 case 语句来描述

  • case 语句里必须是一个 IO 操作

  • select语句中,会按顺序从头至尾评估每一个发送和接收的语句,如果其中的任意一语句可以继续执行(即没有被阻塞),那么就从那些可以执行的语句中任意选择一条来使用

  • 如果 case 条件中都是阻塞的,那么 select 就会走 default 语句,没有 default 语句就会处于一直等待状态,直到任意一条 case 条件成立

  • 一般不建议写 default,写了话,走 default 的概率太大

  • select 一般与 for 循环搭配使用,

超时操作

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go func() {
        for {
            <-ch1
            fmt.Println("get ch1")
        }

    }()
    go func() {
        for {
            <-ch2
            fmt.Println("get ch2")
        }
    }()

    for {
        select {
        case ch1 <- 1:
        case ch2 <- 2:
        case <-time.After(time.Second * 1):
            fmt.Println("tiem out .................")
        }
    }
}
func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go func() {
        for {
            <-ch1
            fmt.Println("get ch1")
        }

    }()
    go func() {
        for {
            <-ch2
            fmt.Println("get ch2")
        }
    }()

    for {
        select {
        case ch1 <- 1:
        case ch2 <- 2:
        case <-time.After(time.Microsecond * 50):
            fmt.Println("tiem out .................")
        }
    }
}
  • 第一段代码最后输出结果要么是 get ch1,要么是 get ch2,到最后都没看到 time out ...,这是为什么?

  • 第二段代码最后输出结果是打印多次 time out ....,这是为什么?

  • 回过头看一下 select 的定义,其中有一句话是这样的:评估每一条 case 语句,任意选择一条未阻塞的语句执行

  • 第一段代码 ch1、ch2 将数据发送到下游管道的时间,是明显短于定时器 1 秒,此时定时器相对于它们是处于阻塞状态的

  • 第二段代码 ch1、ch2、tiem 都将会被 select 考虑,因为 ch1、ch2 管道的流动速度不是每次都比定时器的 50 微秒快的

实际运用

  • 例如聊天室,当客户端连接到服务器,此时我们就开一个协程,基本代码如上,for 循环里面利用 select 不断监听管道流动,定时器时间为 20 秒

  • 20 秒钟内,其他管道都处于阻塞状态,也就是没有客户数据的流入,那么 select 将会执行定时器内的操作,操作大多是 return,结束循环,触发 defer,关闭 conn 连接

猜你喜欢

转载自www.cnblogs.com/cnloop/p/9417135.html