几点注意: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