golang why can not pass value to channel on the main thread

huangapple go评论69阅读模式
英文:

golang why can not pass value to channel on the main thread

问题

case1:

package main

func main()  {
	dogChan := make(chan int)
	dogChan <- 1
}
致命错误:所有的goroutine都处于休眠状态-死锁!

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

case2:

package main

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

	go func(ch chan int) {
		
	}(dogChan)
	dogChan <- 1
}
致命错误:所有的goroutine都处于休眠状态-死锁!

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

case3:

package main

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

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

case4:

package main

func main()  {
	dogChan := make(chan int)
	
	go func(ch chan int) {
		<- ch
	}(dogChan)
	dogChan <- 1
	dogChan <- 2
}
致命错误:所有的goroutine都处于休眠状态-死锁!

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

case5:

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是正常的吗?

英文:

case1

package main

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

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

case2

package main

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

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

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

case3

package main

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

	go func(ch chan int) {
		&lt;- ch
	}(dogChan)
	dogChan &lt;- 1
}

case4

package main

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

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

case5

package main

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

	go func(ch chan int) {
		for {
			select {
				case &lt;- ch:
			}
		}

	}(dogChan)
	dogChan &lt;- 1
	dogChan &lt;- 2
	dogChan &lt;- 3
	dogChan &lt;- 4
	dogChan &lt;- 5
}

Could anyone tell me why case1, case2 got errors while case3 is ok?
In case1 my guess is that dogChan is not used in goroutine so it is treated to be closed.
In case2 my guess is that although dogChan is passed in goroutine but it is not used in goroutine so it is treated to be closed

Could anyone tell me why case4 got errors while case5 is ok?

答案1

得分: 5

你认为在case1case2中发生了什么?通道的作用是作为发送方和接收方之间的同步原语。你有一个发送方在通道dogChan上发送数据,但没有接收方接收它。
没有接收goroutine或goroutine上的接收操作,发送方将会被阻塞(因为是无缓冲通道)。

case4中也存在同样的问题,你在通道上进行了两次发送,但在goroutine中只有一次接收。dogChan <- 2将永远被阻塞。在case5中,如果你的意图是从通道中读取数据,可以使用range循环来迭代接收到的连续值。

英文:

Why do you think thats happening in case1 and case2? The channels are meant to behave as a synchronisation primitive between a sender and receiver. You have a sender sending on a channel, dogChan but none is receiving on it.
Without a receiving goroutine or a receive operation on a goroutine, the sender simply blocks (being a unbuffered channel)

Same problem on case4, you have two sends on the channel, but a single receive on the goroutine. The dogChan &lt;- 2 will block forever. In case5, if your intention was to read from the channel, simply use a range loop to iterate over the successive values sent over it.

答案2

得分: 4

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

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

  • case1,case2 = 向通道发送一条消息,阻塞等待读取者,读取零条消息
  • case4 = 向通道发送一条消息,阻塞等待读取者,读取者不消费(读取)消息
  • case3 = 向通道发送一条消息,从通道中消费一条消息,发送方阻塞等待读取者
  • case5 = 向通道发送五条消息,消费所有(五条)消息,每次发送都会阻塞,直到读取者接收到消息
    // 使用for range遍历通道
    for msg := range ch {
        // 处理消息
    }
    
    // 使用for select
    done := false
    for !done {
        select {
            case msg := <-ch: {
                // 处理消息
            }
            case ch == nil: {
                done = true
            }
        }
    }
    
    // 生产者应该关闭通道
    close(ch)

注意:

  • 通道可以是有缓冲的,可以指定通道(队列)的大小
  • 通道大小默认为1(无缓冲),当通道满时,写入者会被阻塞
英文:

Golang expects program to read message(s) placed into channel.

Consumer (reader) needs to drain (read) all messages from channel, either using simple for-read, or for-select. Channel send and receive both block until sender and receiver are ready.

  • case1, case2 = send one message to channel, block awaiting reader, read zero messages
  • case4 = send one message to channel, block awaiting reader, reader does not consume (read) message
  • case3 = send one message to channel, consume one message from channel, sender blocks awaiting reader
  • case5 = send five messages to channel, consume all (five) messages, each send blocks until reader receives
    // for range over channel
    for msg := range ch {
        // process msg
    }
    
    // for select
    done := false
    for !done {
        select {
            case msg := &lt;-ch: {
                // process msg
            }
            case ch == nil: {
                done = true
            }
        }
    }
    
    // producer should close channel
    close(ch)

Note:

  • channel can be buffered, specify a channel (queue) size
  • channel size default = 1 (unbuffered), writer blocks when channel full

huangapple
  • 本文由 发表于 2021年8月19日 08:28:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/68840691.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定