golang channel & select

golang channel & select

96 大漠狼道 关注

 0.1 2015.11.02 00:51* 字数 886 阅读 3582评论 0喜欢 7

通过消息来共享数据是golang的一种设计哲学,channel则是这种哲理的体现.
channel定义

var varName chan dataType

dataType非常广泛,可以是基本的string,int等,也可以是map,slice,自定义的type类型,甚至可以是channel。类型非常丰富,因而在golang中很容易做到通过消息来共享数据。

初始化

channel通过make来初始化;未初始化的channel为nil(刚接触的会常常碰到因未初始化而导致的死锁问题).
channel通过箭头<-反向来初始化为单向通道,即只读"<- chanName"、只写"<- chanName",省略箭头表示双通道,默认为双通道.
当buffer size为0或者缺失时,这时我们称之为unbuffered;反之则为buffered channel.

阻塞条件

  • 未初始化的channel,一直会阻塞
  • unbuffered channel: 读和写同时准备好了,channel才会开始通信,只有读或者写,则会一直阻塞.
  • buffered channel里面写数据时,直到写满为止才会阻塞,而读则是直到为channel为空时才会阻塞.

不带buffer的channel很容易实现顺序执行、同步等;而带buffer的channel通常用来处理异步事件,只要往里面一扔就撤.

关闭channel

可以用close来关闭channel,但是close后,里面的数据还是会存在,直到被全部消费掉,而已再有些释放资源的地方,close channel后,通过len(channel)来判断剩余资源,并做相应的处理.
对了,这里还有个小细节:

v,ok := <- chan

很多地方都会说通过上面那种方式来判断channel是否关闭.其实这种说法会带个小坑.如果是buffer channel,close()后,如果里面还有数据的话,上面那种方式还是能取到数据,ok也是为true,什么时候会获取不到呢?那就是里面的数据全都消耗完了之后,ok为false.
因而上面的表达式表述为如下更合理些:

v,ok:=<-chan,用来表述为能否从channel获取数据,如果能取到,ok为true,如果取不到ok为false,同时channel已关闭或不存在.

有个比较常用,但新手会觉得奇怪的地方就是:

chan <- struct{}{}

语义为将一个空数据传递给channel.因为struct{}{}占用的内存非常小,而且我们对数据内容也不关心,通常用来做信号量来处理,例如结束某个service等.

select

表达式:

select{
case :
/*...*/
default:
/*...*/
}

通常用在需要处理多个channel的地方.select会一直堵塞,直到某个case收到消息后,但是如果有default case的话,其他case没收到消息的话,会马上走default case,然后整个select语句结束.

for ... select

通常用for ... select语句来循环处理消息,有两个点需要稍微注意下.
1.�break可以用于select语句,因而在break语句里面是不能中断整个for循环的.那想跳出for循环怎么办呢?用标签:

LOOP:
    for{
        select{
            case ....:
                break LOOP  //@A
        }
      }

注意上面@A的地方

2.select语句中是阻塞的,也就是说,直到选中的case执行完了之后,才会进入下一个循环.因而需要耗时的事情不要放在里面处理,可以单独开个go routine来处理.

小礼物走一走,来简书关注我

猜你喜欢

转载自blog.csdn.net/jfkidear/article/details/89069748