golang select channel 多路复用

select多路复用

这个概念与socket网络编程中的select、poll和epoll中的select概念类似。其含义是有N个channel,只要有一个channel上有数据产生,select就会立即监听到,然后接收数据,处理数据,如果有多个channel队列上都有数据流,则随机选取一个channel;如果N个channel上都没有数据流,则一直发生阻塞。例如, 火箭既可以倒计时发射,也可以在倒计时期间取消发射:

// 倒计时
func countdown(count chan struct{}) {
    tick:=time.Tick(1*time.Second)
    for i:=10; i>0; i-- {
        fmt.Printf("countdown: %d\n", i)
        <-tick
    }
    count<-struct{}{}
    return
}
// 中断发射
func abort(ach chan struct{}) {
    os.Stdin.Read(make([]byte, 1))
    ach<- struct{}{}
    return
}

func main() {
    var count = make(chan struct{})
    var ach = make(chan struct{})
    go countdown(count)
    go abort(ach)
    select {
        case <-count:
            launch()
        case <-ach:
            fmt.Println("abort launch...")
    }
    return
}

也可以使用time.After(10*time.Second), 也表示10s后发射。这个例子其实有goroutine泄露,因为tick所在的发送端是一个未知的goroutine,它会每隔1s会向tick channel发送一个数据。程序结束时,也没有关闭goroutine。除非是程序隐式地做。

// 一个更友善的方法:
ticker := time.NewTimer(1*time.Second)
<-ticker.C
ticker.Stop() // 它会触发timer的goroutine主动退出

在使用select时,经常用到的一个场景就是web服务处理请求,如果一个请求处理的时间过长或者负载过高导致的处理时间过长,它会拖慢整个服务端性能,这时候应该尽早让处理时间过长的请求去释放资源。

select {
    case <-ch1:
        // ch1所在的发送端goroutine正在处理请求
    case <-time.After(2*time.Second):
        // 释放资源,返回请求处理失败的数据,或者先通知用户已处理成功,最终一致性可以保证。
        // 最重要的是快速响应,免得用户看着页面没反应,过多的点击按钮发送请求,会过多消耗服务端的系统资源
}

面试题select

ch := make(chan int, 1)
for i := 0; i < 10; i++ {
    select {
    case x := <-ch:
        fmt.Println(x) 
    case ch <- i:
    }
}

问输出结果是什么?

结果:"0" "2" "4" "6" "8", 因为select多路复用中的两个channel其实是同一个,一个用来发送,一个用来接收。所以每当执行ch<-i都是跳跃的,所以每次往ch中发送数据都是偶数了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值