Golang中通道容量问题的探讨
Golang中通道容量问题的探讨
- 当尝试向通道写入第 N+2 个或第 N+1 个值时,此程序是否会被阻塞?考虑到输出结果,可能会认为阻塞发生在第 N+2 次写入时,但我们知道理论上应该是在第 N+1 次写入时发生阻塞。那么实际情况究竟是怎样的呢?
- 如果我们将输出 “generator finish” 的那行代码放在 close(out) 之后,那么程序的输出将不总是包含 “generator finish” 这一行 - 这是为什么?
package main
import (
"fmt"
)
func main() {
in := make(chan int, 1)
go func(out chan<- int) {
for i := 0; i < 3; i++ {
fmt.Println("before", i)
out <- i
fmt.Println("after", i)
}
fmt.Println("generator finish")
close(out)
}(in)
for i := range in {
fmt.Println("_____get", i)
}
}
before 0 after 0 before 1 after 1 before 2 _____get 0 _____get 1 _____get 2 after 2 generator finish
更多关于Golang中通道容量问题的探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html
两篇帖子已合并至现有主题:Channel capacity definition
更多关于Golang中通道容量问题的探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在 Go 语言中,通道的容量决定了它可以缓冲的元素数量。对于容量为 N 的缓冲通道,当通道已满(即已有 N 个元素)时,尝试写入第 N+1 个值会阻塞,直到有空间可用。在您的代码中,通道 in 的容量为 1,因此:
-
阻塞行为分析:当通道已有一个元素时,尝试写入第二个值(即第 N+1 次写入)会阻塞。在您的示例中,输出显示 “before 0” 后立即写入 0(通道为空,不阻塞),然后输出 “after 0”。接着 “before 1” 后尝试写入 1,但此时通道已满(有值 0),因此写入阻塞,直到主协程从通道读取值 0(输出 “_____get 0”),之后写入 1 完成,输出 “after 1”。类似地,写入 2 时也可能阻塞,取决于时机。理论上,阻塞发生在第 N+1 次写入(即第二次写入),但实际输出顺序受调度影响。例如,在您的输出中,写入 1 后没有立即阻塞,因为主协程及时读取了值。
-
"generator finish" 输出问题:如果将
fmt.Println("generator finish")放在close(out)之后,由于close操作不会阻塞,但主协程在range in循环中一旦通道关闭就会退出,这可能导致生成器协程中的fmt.Println("generator finish")未执行或输出被截断,尤其是在程序退出时。如果主协程先退出,整个程序终止,生成器协程可能来不及输出。例如:
// 修改后的代码示例:将输出放在 close 之后
go func(out chan<- int) {
for i := 0; i < 3; i++ {
fmt.Println("before", i)
out <- i
fmt.Println("after", i)
}
close(out)
fmt.Println("generator finish") // 这行可能不会输出
}(in)
在快速执行环境中,主协程在通道关闭后立即结束循环并退出程序,可能中断生成器协程的输出。要确保输出,可添加同步机制,如使用 sync.WaitGroup,但根据问题,不扩展建议。总之,输出不总是包含 “generator finish” 是因为程序退出时机不确定,导致协程未完成输出。

