我刚开始学习golang,在进行并发时,我不小心编写了以下代码:
import (
"fmt"
)
func squares(c chan int) {
for i := 0; i < 4; i++ {
num := <- c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main start")
c := make(chan int)
go squares(c)
c <- 1
c <- 2
c <- 3
c <- 4
go squares(c)
c <- 5
c <- 6
c <- 7
c <- 8
fmt.Println("main stop")
}
最初我应该分配c := make(chan int, 3)
。我无法理解所编写代码的输出。
main start
1
4
9
25
36
49
16
main stop
我想了解代码是如何执行的。我期望发生错误:所有goroutine都在睡着-死锁!
非常感谢!
最佳答案
我不确定您是否真正想要实现什么,尤其是那个怪异循环的原因:
for i := 0; i < 4; i++ {
num := <- c
fmt.Println(num * num)
}
但不管怎么说。首先,对 channel 和goroutine的工作原理进行一些解释。
channel 是线程安全的消息传递管道,用于在不同的执行上下文之间共享数据。使用
make
指令创建 channel ,然后c := make(chan int, 3)
意味着创建一个int类型的 channel ,其“缓冲区”大小为3。要理解此元素非常重要。 channel 确实遵循以该规则为基础的生产者/消费者模式:对于生产者:
对于消费者:
请注意,可以使用
select
指令提供的某些特殊模式将所有阻止操作都变为非阻止,但这是另一个主题:)。Goroutine是轻型子流程,例程(无线程)。这里没有地方进行详细解释,但是重要的是1个goroutine === 1个执行栈。
因此,在您的情况下,只有一个消费者之前,输出是可以预测的。一旦启动第二个Goroutine,消耗顺序仍然是可预测的( channel 的大小只有一个),但是执行顺序却不可!
值得注意的是:您只有7个输出...这是因为您的主goroutine在它发生之前就结束了,从而终止了整个程序的执行。那一点说明了为什么没有
all goroutines are asleep - deadlock!
。如果您想拥有它,您只需要在main的末尾添加
<- c
即可:package main
import (
"fmt"
)
func squares(c chan int) {
for i := 0; i < 4; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main start")
c := make(chan int)
go squares(c)
c <- 1
c <- 2
c <- 3
c <- 4
go squares(c)
c <- 5
c <- 6
c <- 7
c <- 8
<-c
fmt.Println("main stop")
}
您将拥有我认为您期望的行为:main start
1
4
9
25
36
49
64
16
fatal error: all goroutines are asleep - deadlock!
编辑:逐步执行: // a goroutine is created and c is empty. because
// the code of `squares` act as a consumer, the goroutine
// "block" at instruction `num := <-c`, but not the main goroutine
go squares(c)
// 1 is pushed to the channel. Till "c" is not full the main goroutine
// doesn't block but the other goroutine may be "released"
c <- 1
// if goroutine of squares has not consume 1 yet, main goroutine block
// untill so, but is released just after
c <- 2
// it continues with same logic
c <- 3
c <- 4
// till main goroutine encountered `<- c` (instruction I added) .
// Here, it behave as a consumer of "c". At this point all
// goroutine are waiting as consuler on "c" => deadlock
关于go - 问题理解Golang并发代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62875248/