【问题标题】:Go channel readynessGo 频道准备就绪
【发布时间】:2019-10-09 05:14:03
【问题描述】:

我正在尝试理解 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)
}

整数从 goroutine 成功传递到主程序。是什么让这个程序发挥作用?为什么第二个有效但第一个无效? goroutine会造成一些差异吗?

【问题讨论】:

  • 也许这篇文章会有所帮助 - medium.com/rungo/…
  • “我们如何确定发送者和接收者的准备情况” - 你不知道。您编写的代码并不关心它们的准备情况(这基本上是通道的目的,异步消息传递)。您的第一个代码死锁是因为它尝试同步进行异步消息传递,第二个代码可以工作,因为它同时发送和接收。

标签: go channel


【解决方案1】:

让我们单步执行第一个程序:

// 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并尝试从通道接收。第二个线程将等待发送,直到发送为止。

【讨论】:

    【解决方案2】:

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

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

    您需要有一个并发的 go 例程,以便在您写入时从通道读取。并发与通道使用密切相关。

    【讨论】:

      猜你喜欢
      • 2012-02-15
      • 1970-01-01
      • 2011-07-08
      • 1970-01-01
      • 1970-01-01
      • 2015-10-20
      • 2017-07-05
      • 2015-07-01
      • 2020-12-06
      相关资源
      最近更新 更多