Go 读写一个 nil 通道会使协程永久挂起,为什么这样设计呢?

2022-05-18 14:41:19 +08:00
 xing393939

写了一个 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 掉,所以官方为什么这样做呢

.

.

.

1659 次点击
所在节点    Go 编程语言
4 条回复
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.
pathletboy
2022-05-18 14:51:25 +08:00
https://go.dev/ref/spec#Channel_types
A nil channel is never ready for communication.
zzn
2022-05-18 15:03:22 +08:00
> 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
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)
}
}
}
}

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/853708

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX