!无论怎样都不应该在接收端关闭 channel
,因为在接收端无法判断发送端是否还会向通道中发送元素值
!试图向已经关闭的 channel
发送数据会导致 panic
!关闭已经关闭的 channel
会导致 panic
以下均为亲自测试及其总结,demo 仅供参考,总结自云栖社区
关闭原则(正常方式):
不在接收端关闭(常用于 1-N,由发送端来关闭)
不要关闭有多个并发发送者的 channel(常用于 N-1,由接收端来通知)
3 种优雅的关闭场景模型:1-N N-1 M-N
(生产者-消费者)以及几种不优雅的关闭方式
场景 1
1 个发送者 1 个接收者(最简单的)
发送端直接关闭 channel
场景 2
N 个发送者 1 个接收者
添加一个 停止通知 接收端告诉发送端不要发送了
场景 3
N 个发送者 M 个接收者
检查 channel
是否关闭(有局限性)
非正常方式(以下几种从来没尝试过,今天学到了)
1、使用锁来关闭
type T int
type MyChannel struct {
C chan T
closed bool
mutex sync.Mutex
}
func NewMyChannel() *MyChannel {
return &MyChannel{C: make(chan T)}
}
func (this *MyChannel) SafeClose() {
this.mutex.Lock()
if !this.closed {
close(this.C)
this.closed = true
}
this.mutex.Unlock()
}
func (this *MyChannel) IsClosed() bool {
this.mutex.Lock()
defer this.mutex.Unlock()
return this.closed
}
2、使用 sync.once
来关闭
type MyChannel struct {
C chan T
once sync.Once
}
func NewMyChannel() *MyChannel{
return &MyChannel{C: make(chan T)}
}
func (this *MyChannel) SafeClose() {
this.once.Do(func(){
close(this.C)
})
}
3、使用 recover()
来关闭
type T int
func SafeSend(ch chan T, value T) (closed bool) {
defer func() {
if recover() != nil {
closed = true
}
}()
ch <- value
return false
}
func SafeClose(ch chan T) (closed bool) {
defer func() {
if recover() != nil {
closed = false
}
}()
close(ch)
return true
}
以上 3 种非优雅的关闭方式暂未测试,明天再写 demo
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于