去渠道准备

Go channel readyness

我想了解 Go 中的通道。我读过默认情况下发送和接收块,直到发送方和接收方都准备好。但是我们如何确定发送方和接收方的准备情况。

例如下面的代码

package main

import "fmt"

func main() {
    ch := make(chan int)
    ch <- 1

    fmt.Println(<-ch)
}

程序将卡在通道发送操作上,永远等待有人读取值。即使我们在 println 语句中有一个接收操作,它也会以死锁结束。

但对于下面的节目

package main

import "fmt"

func main() {
    ch := make(chan int)

    go func () {
        ch <- 1
    }()

    fmt.Println(<-ch)
}

整数从go routine 成功传递到主程序。是什么让这个计划奏效?为什么第二个有效但第一个无效? go routine 会造成一些差异吗?

让我们逐步完成第一个程序:

// My notes here
ch := make(chan int)  // make a new int channel
ch <- 1               // block until we can send to that channel
                      // keep blocking
                      // keep blocking
                      // still waiting for a receiver
                      // no reason to stop blocking yet...

// this line is never reached, because it blocks above forever.
fmt.Println(<-ch)

第二个程序将发送拆分到它自己的执行行中,所以现在我们有:

ch := make(chan int)  // make a new int channel

go func () {          // start a new line of execution
    ch <- 1           // block this second execution thread until we can send to that channel
}()

fmt.Println(<-ch)     // block the main line of execution until we can read from that channel

由于这两条执行线可以独立工作,主线可以下到 fmt.Println 并尝试从频道接收。第二个线程将等待发送直到发送。

go 例程绝对不同。写入通道的 go 例程将被阻塞,直到您的主函数准备好从 print 语句中的通道读取。有两个并发线程,一个读取一个写入,满足双方的准备。

在您的第一个示例中,单个线程被通道写入语句阻塞,永远不会到达通道读取。

您需要有一个并发的 go 例程,以便在您写入通道时从通道读取。并发性 hand-in-hand 随通道使用而变化。