在阅读client-go代码时发现源码对channel的部分使用方式不太理解,一个是单项channel的使用,一个是nil值channel的使用,于是搜索总结一下。
在golang中可以定义channel为双向的,也可以将channel定义为只能接收或只能发送类型的,如下面所示:
// You can edit this code!
// Click here and start typing.
package main
func main() {
// 普通双向的
var normalCh chan interface{}
// 只能发送
var sendOnlyCh chan<- interface{}
// 只能接收
var receiveOnlyCh <-chan interface{}
<-sendOnlyCh
receiveOnlyCh <- 1
}
编译上述代码,将会得到下列错误:
./prog.go:12:2: invalid operation: <-sendOnlyCh (receive from send-only type chan<- interface {})
./prog.go:13:16: invalid operation: receiveOnlyCh <- 1 (send to receive-only type <-chan interface {})
Go build failed.
可以看到读取只发送channel和写只接收channel都会编译出错,但是普通的channel则既可以读取又可以发送,如下面这个例子,这个例子在goroutine中定义了一个双向读写的channel,但是返回值类型是只读类型,在这个goroutine中可以对这个channel进行读写,但是调用F()通过返回值拿到的channel只能读取:
func F() <-chan int {
// Create a regular, two-way channel.
c := make(chan int)
go func() {
defer close(c)
// Do stuff
c <- 123
}()
// Returning it, implicitely converts it to read-only,
// as per the function return value.
return c
}
go中,可以对nil值channel进行读写操作,当对值为nil的channel进行读取操作时会阻塞,但是对值为nil值的channel调用close()会panic。使用nil值channel可以帮助在select中禁用某个select分支,因为阻塞了所以都不会进入分支语句。
下面是client-go中对nil值channel和单向channel的使用的函数代码:
func (p *processorListener) pop() {
defer utilruntime.HandleCrash()
defer close(p.nextCh) // Tell .run() to stop
var nextCh chan<- interface{}
var notification interface{}
for {
select {
case nextCh <- notification:
// Notification dispatched
var ok bool
notification, ok = p.pendingNotifications.ReadOne()
if !ok { // Nothing to pop
nextCh = nil // Disable this select case
}
case notificationToAdd, ok := <-p.addCh:
if !ok {
return
}
if notification == nil { // No notification to pop (and pendingNotifications is empty)
// Optimize the case - skip adding to pendingNotifications
notification = notificationToAdd
nextCh = p.nextCh
} else { // There is already a notification waiting to be dispatched
p.pendingNotifications.WriteOne(notificationToAdd)
}
}
}
}