【问题标题】:golang why can not pass value to channel on the main threadgolang为什么不能在主线程上将值传递给通道
【发布时间】:2021-10-20 17:45:32
【问题描述】:

案例1

package main

func main()  {
    dogChan := make(chan int)
    dogChan <- 1
}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /Users/xuzhongwei/Source/awesomeProject/main.go:5 +0x50

案例2

package main

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

    go func(ch chan int) {
        
    }(dogChan)
    dogChan <- 1
}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /Users/xuzhongwei/Source/awesomeProject/main.go:9 +0x72

案例3

package main

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

    go func(ch chan int) {
        <- ch
    }(dogChan)
    dogChan <- 1
}

案例4

package main

func main()  {
    dogChan := make(chan int)
    
    go func(ch chan int) {
        <- ch
    }(dogChan)
    dogChan <- 1
    dogChan <- 2
}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /Users/xuzhongwei/Source/awesomeProject/main.go:10 +0x90

案例5

package main

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

    go func(ch chan int) {
        for {
            select {
                case <- ch:
            }
        }

    }(dogChan)
    dogChan <- 1
    dogChan <- 2
    dogChan <- 3
    dogChan <- 4
    dogChan <- 5
}

谁能告诉我为什么 case1、case2 出错而 case3 没问题? 在 case1 中,我的猜测是 goroutine 中没有使用 dogChan,因此它被视为关闭。 在 case2 中,我的猜测是虽然 dogChan 是在 goroutine 中传递的,但它没有在 goroutine 中使用,所以它被视为关闭

谁能告诉我为什么 case4 出错而 case5 没问题?

【问题讨论】:

    标签: go goroutine


    【解决方案1】:

    为什么你认为 case1case2 会发生这种情况?通道旨在充当发送方和接收方之间的同步原语。你有一个发送者在一个频道上发送,dogChan,但没有人在它上面接收。 如果没有接收 goroutine 或 goroutine 上的接收操作,发送方只会阻塞(作为无缓冲通道)

    case4 上的同样问题,通道上有两个发送,但 goroutine 上有一个接收。 dogChan &lt;- 2 将永远阻塞。在case5 中,如果您打算从通道中读取,只需使用range 循环来迭代通过它发送的连续值。

    【讨论】:

      【解决方案2】:

      Golang 期望程序读取放入通道中的消息。

      消费者(阅读者)需要使用简单的 for-read 或 for-select 从通道中读取(读取)所有消息。通道发送和接收都阻塞,直到发送方和接收方准备好。

      • case1,case2 = 向频道发送一条消息,阻止等待阅读器,读取零条消息
      • case4 = 向通道发送一条消息,阻塞等待阅读器,阅读器不消费(读取)消息
      • case3 = 向通道发送一条消息,从通道消耗一条消息,发送方阻塞等待阅读器
      • case5 = 向通道发送 5 条消息,消耗所有(5 条)消息,每个发送块直到阅读器接收到
          // for range over channel
          for msg := range ch {
              // process msg
          }
          
          // for select
          done := false
          for !done {
              select {
                  case msg := <-ch: {
                      // process msg
                  }
                  case ch == nil: {
                      done = true
                  }
              }
          }
          
          // producer should close channel
          close(ch)
      

      注意:

      • 通道可以缓冲,指定通道(队列)大小
      • 通道大小默认 = 1(无缓冲),写入器在通道满时阻塞

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-09-02
        • 2017-05-01
        • 2020-09-14
        • 2020-08-07
        • 2020-04-13
        • 1970-01-01
        • 2019-03-22
        • 1970-01-01
        相关资源
        最近更新 更多