Channel關閉原則
不要在消費端關閉channel,不要在有多個並行的生產者時對channel執行關閉操作。
也就是說應該只在[唯一的或者最后唯一剩下]的生產者協程中關閉channel,來通知消費者已經沒有值可以繼續讀了。只要堅持這個原則,就可以確保向一個已經關閉的channel發送數據的情況不可能發生。
暴力關閉channel的正確方法
如果想要在消費端關閉channel,或者在多個生產者端關閉channel,可以使用recover機制來上個保險,避免程序因為panic而崩潰。
func SafeClose(ch chan T) (justClosed bool) {
defer func() {
if recover() != nil {
justClosed = false
}
}()
close(ch)
return true
}
使用這種方法明顯違背了上面的channel關閉原則,然后性能還可以,畢竟在每個協程只會調用一次SafeClose,性能損失很小。
同樣也可以在生產消息的時候使用recover方法。
禮貌關閉channel方法
還有不少人經常使用sync.Once來關閉channel,這樣可以確保只會關閉一次
同樣我們也可以使用sync.Mutex達到同樣的目的。
要知道golang的設計者不提供SafeClose或者SafeSend方法是有原因的,
他們本來就不推薦在消費端或者在並發的多個生產端關閉channel,
比如關閉只讀channel在語法上就徹底被禁止使用了。
優雅的關閉channel的方法
多個消費者,單個生產者.
多個生產者,單個消費者。
就上面這個例子,生產者同時也是退出信號channel的接受者,退出信號channel仍然是由它的生產者