写了一个 demo: https://go.dev/play/p/51-Z_XNr-th
这里写一个 nil 通道会一直阻塞,Go 源码在这一行: https://hub.fastgit.xyz/golang/go/blob/go1.16.10/src/runtime/chan.go#L163
不知道为什么要这样设计?一直阻塞会导致协程泄漏,还不如直接 panic 掉,所以官方为什么这样做呢
.
.
.
1
pathletboy 2022-05-18 14:48:27 +08:00
你贴的这个直接运行
fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan send (nil chan)]: main.main() /tmp/sandbox3073028740/prog.go:11 +0x7e goroutine 5 [chan receive]: main.main.func1() /tmp/sandbox3073028740/prog.go:9 +0x4f created by main.main /tmp/sandbox3073028740/prog.go:7 +0x6a Program exited. |
2
pathletboy 2022-05-18 14:51:25 +08:00
https://go.dev/ref/spec#Channel_types
A nil channel is never ready for communication. |
3
zzn 2022-05-18 15:03:22 +08:00 1
> It's for consistency with select. The semantics of a nil channel are
the same regardless of how it is used. It's useful that it blocks in a select, so that's what it does outside a select. > If it panicked outside a select, not only would it be inconsistent but the channel code would need to behave differently in the two cases, a needless complexity. https://groups.google.com/g/golang-nuts/c/QltQ0nd9HvE/m/VvDhLO07Oq4J |
4
pathletboy 2022-05-18 15:05:54 +08:00
为了灵活性
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) } } } } |