【问题标题】:How to explain channel block mechanism to golang beginners?如何向 golang 初学者解释通道阻塞机制?
【发布时间】:2021-08-24 04:21:42
【问题描述】:

我是一个 golang 初学者,在学习 channel 和 goroutine 时遇到了一些麻烦。我的一个难点是 golang 通道阻塞机制是如何工作的。在golang tour,上面写着By default, sends and receives block until the other side is ready.,我根据自己的理解做了一些实验,得到了结果,fatal error: all goroutines are asleep - deadlock!。这个提示并没有真正让我了解错误是如何发生的。我google了一下,几乎每一篇文章都是关于channel的深层机制,或者假设读者理解了block这个词已经给出了所有的信息。

但作为初学者我有很多疑问,比如:

  • 同一个 go-routine 写入通道后是否可以执行通道读取操作?
  • 如果一个通道被阻塞,其他 go-routine 是否仍然可以向它发送消息?
  • 如果 go-routine 尝试向被阻塞的频道发送消息,会发生什么?它会通过一个错误,或者什么都没发生,还是?

下面是我的一个让我困惑的测试?(据我所知,main func 是一个 go-routine,我认为它在执行过程中是同一个)

package main

import "time"

func chanWrite(s string, ch chan string) {
    ch <- s
    println("write", s)
}

func chanRead(ch chan string) {
    println("read", <- ch)
}

// main func 1
func main() {
    ch := make(chan string)
    go chanWrite("A", ch)
    time.Sleep(time.Second)
}

// main func 1 didn't throw error


// main func 2(modify main func 1 and then execute it)
func main() {
    ch := make(chan string)
    chanWrite("A", ch)
    time.Sleep(time.Second)
}
// main func 2 throw error: "fatal error: all goroutines are asleep - deadlock!"

我在这个测试中看到的是在某种情况下,当我在没有读取的情况下将内容写入通道时,我得到了fatal error,有时什么也没有发生(比如在 main func 1 中)。

那么,有人能以一种简单而有趣的方式解释通道块是如何工作的,以便 golang 初学者可以轻松理解它吗?

【问题讨论】:

    标签: go channel goroutine


    【解决方案1】:

    goroutine 可以阻塞等待通道准备好发送或接收,但通道本身永远不会处于“阻塞”状态。

    第一个程序没有恐慌,因为主函数执行到最后并终止程序。

    同一个go-routine写入通道后是否可以执行通道读操作?

    否,如果通道是无缓冲的(默认)。对于无缓冲通道,发送 goroutine 会阻塞,直到接收 goroutine 准备好。

    单个 goroutine 不能同时执行发送和接收。如果只有一个 goroutine 发送到通道,goroutine 将永远阻塞。

    如果一个通道被阻塞了,其他 go-routine 还能发送消息给它吗?

    goroutine 可以在通道关闭之前的任何时间向通道发送值。 goroutine 可以阻塞等待通道准备好发送。

    如果 go-routine 尝试向被阻塞的频道发送消息,会发生什么?它会通过一个错误,或者什么都没发生,还是?

    goroutine 可以阻塞等待通道准备就绪。通道本身并未处于阻塞状态。

    【讨论】:

      【解决方案2】:

      频道不会“阻塞”。通道上的读取或写入操作可能会阻塞。

      对于一个无缓冲的通道(这就是你上面所说的):写入操作将阻塞写入 goroutine,直到另一个 goroutine 准备好从该通道读取。当读取 goroutine 准备好读取时(即执行

      对于缓冲通道:只要通道缓冲区未满,写入就不会阻塞。同样,如果有内容要从通道读取,则读取不会阻塞。

      至于你的问题:

      1. 如果有问题的通道没有缓冲,写入操作将阻塞,因为只有当另一个 goroutine 正在从通道读取时,写入操作才能继续。所以 goroutine 不会继续从通道中读取。如果这是一个缓冲通道并且通道未满,则同一个 goroutine 可能会写入通道并从中读取。
      2. 如果一个 goroutine 正在等待写入通道,而另一个 goroutine 来写入它,它也会阻塞,直到另一个 goroutine 从通道读取。
      3. 如果一个 goroutine 尝试写入一个已满的通道,它将阻塞,直到另一个 goroutine 可以从该通道读取。

      【讨论】:

        猜你喜欢
        • 2017-06-07
        • 1970-01-01
        • 2021-11-28
        • 2015-04-22
        • 2016-03-11
        • 2017-12-08
        • 2014-07-02
        • 2016-10-12
        • 2016-12-06
        相关资源
        最近更新 更多