Go专家编程 select--case篇

select是golang在语言层面提供的IO多路复用机制,可以检测多个channel是否ready(可读、可写),相比较操作系统层面的IO多路复用还是方便很多。

与select 配合使用的是case和default,default是一种特殊的case。

一:case的数据结构

type scase struct {
    c           *hchan         // chan
    kind        uint16
    elem        unsafe.Pointer // data element
}

c表示当前case语句所操作的channel指针,这也说明了一个case语句只能操作一个channel。

kind表示当前case的类型,是读还是写还是default。分别由常量定义 如下

        caseRecv:case语句中尝试读取c中的数据

        caseSend:case语句中尝试向C中写入数据

        caseDefault:default语句

elem表示缓冲区地址,根据kind不同有不同的作用,如果kind==Recv,elem就表示从c读取数据存放的地方。如果kind==Send,elem就表示向c写入数据 存放的地方。

二:select实现原理

源码包src/runtime/select.go:selectgo()定义了select选择case的函数:

func selectgo(cas0 *scase, order0 *uint16, ncases int) (int, bool)

参数说明:

cas0为scase数组的首地址,selectgo的作用就是从这些cases当中找出一个返回。

order0为一个两倍cas0数组长度的buffer,存放的是scase随机序列(pollorder)+scase中channel的地址序列(lockorder)

        pollorder:每次调用selectgo,都会把scase顺序打乱,以达到随机检测case的目的。

        lockorder:去重防止对channel加锁时重复加锁的目的。

ncases:scases数组的长度

返回值说明:

        int表示返回的case的编号

        bool表示 是否成功从channle中读取了数据,如果选中的case是从channel中读数据,则该返回值表示是否读取成功。

func selectgo(cas0 *scase, order0 *uint16, ncases int) (int, bool) {
    //1. 锁定scase语句中所有的channel
    //2. 按照随机顺序检测scase中的channel是否ready
    //   2.1 如果case可读,则读取channel中数据,解锁所有的channel,然后返回(case index, true)
    //   2.2 如果case可写,则将数据写入channel,解锁所有的channel,然后返回(case index, false)
    //   2.3 所有case都未ready,则解锁所有的channel,然后返回(default index, false)
    //3. 所有case都未ready,且没有default语句
    //   3.1 将当前协程加入到所有channel的等待队列
    //   3.2 当将协程转入阻塞,等待被唤醒
    //4. 唤醒后返回channel对应的case index
    //   4.1 如果是读操作,解锁所有的channel,然后返回(case index, true)
    //   4.2 如果是写操作,解锁所有的channel,然后返回(case index, false)
}

注意事项:

对于读channel的case而言,case elem, ok := <-chan1:,一定要判断是否读取成功。因为如果这个channel在其他地方被close()时,当前这个读也是会返回的,只是读取失败ok为false!!!

总结:

  • select语句中除default外,每个case操作一个channel,要么读要么写
  • select语句中除default外,各case执行顺序是随机的
  • select语句中如果没有default语句,则会阻塞等待任一case
  • select语句中读操作要判断是否成功读取,关闭的channel也可以读取
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值