標籤:忽略 als 代碼 OLE 利用 結果 creat spi only
譯自:https://www.godesignpatterns.com/2014/05/nil-channels-always-block.html
原Alex Lockwood
在本篇文章中,我們將討論 nil channel 在 Go 中的使用。nil channel 無論是接收還是發送都會永久阻塞:
// Create an uninitialized (nil) channel.var ch chan struct{}// Receiving on a nil channel blocks forever.<-ch// Sending on a nil channel will also block forever.ch <- struct{}{}
nil channel 看上去似乎沒有什麼用,甚至曾經在你的項目中引起 bug(例如忘記在使用 channels 前,用 make 初始化)。但是,可以通過幾種巧妙的方式利用此屬性,特別是當你需要在 select 語句中動態禁用一個 case:
if disableSelectCase {ch1 = nil} else {ch1 = nonNilChan}select {case <-ch1:// This case will only be considered if ch1 is not nil.
// 這個 case 直到 ch1 不是 nil 時才會被考慮case <-ch2:// This case will always be considered (assuming ch2 is non-nil).}
上面的 code 闡明了這樣一個特徵,當 select 語句中的一個case 是 nil channel 時,它將會選擇性忽略。如果 boolean 類型的 disableSelectCase 為 true ,此時會將 nil 賦值給 ch1,從而阻止 ch1 channel 被 select 語句考慮。
這種特性也被用來防止空迴圈,比如當你需要等待多個 channels 關閉時:
// WARNING! Spin loop might occur!var isClosed1, isClosed2 boolfor !isClosed1 || !isClosed2 {select {case _, ok := <-ch1:if !ok {isClosed1 = true}case _, ok := <-ch2:if !ok {isClosed2 = true}}}
如果上面的代碼中兩個 channel 有一個被關閉,將會在你的項目中引起一個小 bug。因為被關閉的 channel 永遠不會阻塞,如果 ch1 被關閉,ch1 在隨後的迴圈迭代中將總是準備被接收。作為結果,程式將陷入死迴圈,還有就是 case <- ch2 也許再也沒有機會被執行。
為瞭解決這個問題,我們可以利用 nil channel 總是阻塞的特性:
// Safely disable channels after they are closed.for ch1 != nil || ch2 != nil {select {case _, ok := <-ch1:if !ok {ch1 = nil}case _, ok := <-ch2:if !ok {ch2 = nil}}}
Nil Channels Always Block(Go語言中空管道總是阻塞)