我是 golang 的新手,正在尝试使用 goroutines 试验缓冲通道。我以为我理解了缓冲通道是如何与 goroutine 一起工作的,直到遇到下面的例子,这对我来说是一个脑筋急转弯,并且对我迄今为止所学的概念给予了极大的帮助。
这是我从文章https://medium.com/rungo/anatomy-of-channels-in-go-concurrency-in-go-1ec336086adb中获取的原始示例。
代码#1:(通道容量=3,通道长度=3,环路长度=4)
func squares(c chan int) {
for i := 0; i <= 3; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main() started")
c := make(chan int, 3)
go squares(c)
c <- 1
c <- 2
c <- 3
fmt.Println("main() stopped")
}
输出:
main() started
main() stopped
解释:在上面的程序中,通道 c 的缓冲容量为 3。也就是说它可以容纳 3 个值。由于缓冲区没有溢出(因为我们没有推送任何新值),主 goroutine 不会阻塞并且程序存在。我已经理解了这个例子。
代码#2:(通道容量=3,通道长度=4,环路长度=4)
func squares(c chan int) {
for i := 0; i <= 3; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main() started")
c := make(chan int, 3)
go squares(c)
c <- 1
c <- 2
c <- 3
c <- 4 // goroutine blocks here
fmt.Println("main() stopped")
}
输出:
main() started
1
4
9
16
main() stopped
解释:由于现在填充的缓冲区通过 c <- 4 发送操作获得推送,主 goroutine 块和正方形 goroutine 排出所有值。这也是我理解的。
代码#3:(通道容量=3,通道长度=5,环路长度=5)
func squares(c chan int) {
for i := 0; i <= 4; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main() started")
c := make(chan int, 3)
go squares(c)
c <- 1
c <- 2
c <- 3
c <- 4 // goroutine blocks here
c <- 5
fmt.Println("main() stopped")
}
输出:
main() started
1
4
9
16
25
main() stopped
说明:我为通道添加了另一个值,即 5。虽然通道容量只有 3。
我知道在通道接收到 n+1 个发送操作之前,它不会阻塞当前的 goroutine。在值 4 上,它接收 n+1 操作,这就是 goroutine 被阻塞并耗尽所有值的原因,但我无法理解的是通道如何处理 n+2 操作。是不是因为我们已经从通道中读取了值,并且我们有更多的阅读空间?