猿问

通道阻塞顺序

我想了解频道在 golang 中的工作方式。我的代码非常简单,但输出却令人惊讶。


正如文档所述:从通道读取和写入通道会阻塞当前的 goroutine,因此我认为写入通道会阻塞通道,直到主例程产生为止。


package main


func rtn(messages chan<- string) {

    defer close(messages)


    println("p1")

    messages <- "ping1"


    //for i := 0; i < 10000000; i++ { }


    println("p2")

    messages <- "ping2"

}


func main() {

    messages := make(chan string)

    go rtn(messages)


    for msg := range messages {

        println(msg)

    }

}

我以为它会打印


p1

ping1

p2

ping2

但它实际上打印


p1

p2

ping1

ping2


回首忆惘然
浏览 125回答 1
1回答

森林海

您正在使用一个无缓冲的通道,它作为主 goroutine 和第二个 goroutine 之间的同步点。在这种情况下,你只知道当第二个 goroutine 在这里时,messages <- "ping1"主要的 goroutine 在 line 上for msg := range messages。因此,不能保证主循环println(msg)立即到达。也就是说,与此同时,第二个 goroutine 可以继续前进并到达 lines println("p2")and messages <- "ping2"。作为一个反例,我添加一个通道只是为了强制打印之间的完全同步。package mainfunc rtn(messages chan<- string, syncChan chan struct{}) {&nbsp; &nbsp; defer close(messages)&nbsp; &nbsp; println("p1")&nbsp; &nbsp; messages <- "ping1"&nbsp; &nbsp; //Wait for main goroutine to print its message&nbsp; &nbsp; <-syncChan&nbsp; &nbsp; //for i := 0; i < 10000000; i++ { }&nbsp; &nbsp; println("p2")&nbsp; &nbsp; messages <- "ping2"&nbsp; &nbsp; //Wait for main goroutine to print its message&nbsp; &nbsp; <-syncChan}func main() {&nbsp; &nbsp; messages := make(chan string)&nbsp; &nbsp; syncChan := make(chan struct{})&nbsp; &nbsp; go rtn(messages, syncChan)&nbsp; &nbsp; for msg := range messages {&nbsp; &nbsp; &nbsp; &nbsp; println(msg)&nbsp; &nbsp; &nbsp; &nbsp; //Notify the second goroutine that is free to go&nbsp; &nbsp; &nbsp; &nbsp; syncChan <- struct{}{}&nbsp; &nbsp; }}打印出您期望的输出:p1ping1p2ping2这是另一个产生您正在寻找的输出的示例。在这种情况下,主 goroutine 被time.Sleep(). 这将使第二个 goroutine 在接收器准备好接收之前准备好发送。因此,发送方实际上会阻塞发送操作。package mainimport (&nbsp; &nbsp; "time")func rtn(messages chan<- string) {&nbsp; &nbsp; defer close(messages)&nbsp; &nbsp; println("p1")&nbsp; &nbsp; messages <- "ping1"&nbsp; &nbsp; //for i := 0; i < 10000000; i++ { }&nbsp; &nbsp; println("p2")&nbsp; &nbsp; messages <- "ping2"}func main() {&nbsp; &nbsp; messages := make(chan string)&nbsp; &nbsp; go rtn(messages)&nbsp; &nbsp; //Put main goroutine to sleep. This will make the&nbsp; &nbsp; //sender goroutine ready before the receiver.&nbsp;&nbsp; &nbsp; //Therefore it will have to actually block!&nbsp; &nbsp; time.Sleep(time.Millisecond * 500)&nbsp; &nbsp; for msg := range messages {&nbsp; &nbsp; &nbsp; &nbsp; println(msg)&nbsp; &nbsp; }}
随时随地看视频慕课网APP

相关分类

Go
我要回答