幾點注意:go的無緩存通道
通道make 創建后,即使里面是空的,也可以取里面內容。但是程序會被阻塞。
通道的規則是沒人取,是不能往里面放的。放的線程會阻塞。
最外層的requestChan相當於一個總線或媒介。
生產者goroutineD直接從requestChan通道里面再取一個內部通道responseChan,這時不管responseChan創建沒有,如果沒有的話會阻塞,直到取到后,往responseChan通道里面扔內容。
消費者goroutineC創建一個內部通道responseChan,然后就可以提取里面的內容。如果沒有阻塞直到收到。
收取開始后,requestChan中介通道里面就沒有responseChan內部通道了?
package main import "fmt" import "time" func main() { // make the request chan chan that both go-routines will be given requestChan := make(chan chan string) // start the goroutines go goroutineC(requestChan) go goroutineD(requestChan) // sleep for a second to let the goroutines complete time.Sleep(20 * time.Second) } func goroutineC(requestChan chan chan string) { time.Sleep(5 * time.Second) fmt.Println("goroutineC create response chan.") // make a new response chan responseChan := make(chan string) // send the responseChan to goRoutineD requestChan <- responseChan fmt.Println("goroutineC waiting to read.") // read the response response := <-responseChan fmt.Println("goroutineC get Response: ", response) } func goroutineD(requestChan chan chan string) { // read the responseChan from the requestChan fmt.Println("\t\tgoroutineD wait to get response chan.") responseChan := <-requestChan fmt.Println("\t\tgoroutineD has gotten response chan.") fmt.Println("\t\tgoroutineD sleep 5 minutes.") time.Sleep(5 * time.Second) // send a value down the responseChan fmt.Println("\t\tgoroutineD send wassup.") responseChan <- "wassup!" }
改成如下代碼執行,發現通道的內容生成好之后也無法放入通道,需要有人取內容時,才能放入。這是go的無緩存通道規則。
package main import "fmt" import "time" func main() { // make the request chan chan that both go-routines will be given requestChan := make(chan chan string) // start the goroutines go goroutineC(requestChan) go goroutineD(requestChan) // go goroutineC(requestChan) // go goroutineD(requestChan) // sleep for a second to let the goroutines complete time.Sleep(40 * time.Second) } func goroutineC(requestChan chan chan string) { fmt.Println("goroutineC create response chan.") // make a new response chan responseChan := make(chan string) // send the responseChan to goRoutineD requestChan <- responseChan fmt.Println("goroutineC waiting to read.") // read the response response := <-responseChan fmt.Println("goroutineC get Response: ", response) ////read again///////// // read the response response = <-responseChan fmt.Println("goroutineC get Response: ", response) } func goroutineD(requestChan chan chan string) { time.Sleep(5 * time.Second) // read the responseChan from the requestChan fmt.Println("\t\tgoroutineD wait to get response chan.") responseChan := <-requestChan fmt.Println("\t\tgoroutineD has gotten response chan.") fmt.Println("\t\tgoroutineD sleep 5 minutes.") time.Sleep(5 * time.Second) // send a value down the responseChan fmt.Println("\t\tgoroutineD send wassup.") responseChan <- "wassup!" /////Send again to check if response chan dissapear/////////////// fmt.Println("\t\tgoroutineD sleep 5 minutes.") time.Sleep(5 * time.Second) // send a value down the responseChan fmt.Println("\t\tgoroutineD send w22222222222.") responseChan <- "w22222222222!" }
執行結果:
goroutineC create response chan.
goroutineD wait to get response chan.
goroutineD has gotten response chan.
goroutineD sleep 5 minutes.
goroutineC waiting to read.
goroutineD send wassup.
goroutineD sleep 5 minutes.
goroutineC get Response: wassup!
goroutineD send wassup.
goroutineC get Response: w22222222222!
參考:http://tleyden.github.io/blog/2013/11/23/understanding-chan-chans-in-go/
https://www.goin5minutes.com/blog/channel_over_channel/
Visual time lapse walkthrough
Keep in mind that Goroutine C is the “real consumer” even though it will be the one which writes to the request channel.
The request channel starts out empty.
Goroutine C passes a “response channel” to go routine D via the request channel
Goroutine C starts reading from the (still empty) response channel.
Goroutine D writes a string to the response channel
Goroutine C now is able to read a value from response channel, and get’s the “wassup!” message
And now we are back to where we started