英文:
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 <- 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 <- 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) {
<- ch
}(dogChan)
dogChan <- 1
}
case4
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
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
}
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
你认为在case1
和case2
中发生了什么?通道的作用是作为发送方和接收方之间的同步原语。你有一个发送方在通道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 <- 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 := <-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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论