Go channel系列:html
當關閉一個channel時,會使得這個channel變得可讀。經過這個特性,能夠實現一個goroutine執行順序的技巧。code
若是一個goroutine A依賴於另外一個goroutine B,在goroutine A中首先經過讀goroutine B來阻塞本身,直到goroutine B關閉自身以後,goroutine A纔會繼續運行。這樣,goroutine B就先於goroutine A運行。htm
下面是一個指定goroutine執行順序的示例,它保證的順序是A()-->B()-->C()
。blog
package main import ( "fmt" "time" ) // A首先被a阻塞,A()結束後關閉b,使b可讀 func A(a, b chan struct{}) { <-a fmt.Println("A()!") time.Sleep(time.Second) close(b) } // B首先被a阻塞,B()結束後關閉b,使b可讀 func B(a, b chan struct{}) { <-a fmt.Println("B()!") close(b) } // C首先被a阻塞 func C(a chan struct{}) { <-a fmt.Println("C()!") } func main() { x := make(chan struct{}) y := make(chan struct{}) z := make(chan struct{}) go C(z) go A(x, y) go C(z) go B(y, z) go C(z) // 關閉x,讓x可讀 close(x) time.Sleep(3 * time.Second) }
上面的示例中:A goroutine被x阻塞,B goroutine被y阻塞,C goroutine被z阻塞。C依賴的z由B關閉,B依賴的y由A關閉。get
如此一來,當main goroutine中的x被關閉後,A()從阻塞中釋放,繼續執行,關閉y,而後B從阻塞中釋放,繼續執行,關閉z,C得以釋放。因爲z被關閉後,z仍然可讀,因此屢次執行C(z)不會出問題。入門
A()和B()不能屢次執行,由於close()不能操做已被關閉的channel。import
注意,上面的channel都是struct{}
類型的,整個過程當中,x、y、z這3個通道都沒有傳遞數據,而是直接關閉來釋放通道,讓某些阻塞的goroutine繼續執行下去。顯然,這裏的x、y、z的做用都是"信號通道",用來傳遞消息。select